Commit Graph
217 Commits
Author SHA1 Message Date
Matt FiddamanandGitHub 132b9db11c use separate_continuous_history_consent flag from GoCardless (#7890)
* use separate_continuous_history_consent flag from GoCardless

* add logging for GCL

* note

* test
2026-05-18 22:29:46 +00:00
3494f78c94 [AI] Restrict secrets API access to admins in OpenID mode (#7862)
* [AI] Require admin for GET /secret/:name in OpenID mode

The GET handler only verified an authenticated session, while the
sibling POST handler enforced an admin gate when the active auth
method is openid. A non-admin BASIC user in an OpenID multi-user
deployment could enumerate which admin-managed bank-sync secrets
were configured by probing 204 vs 404 responses.

Factor the auth-method + admin check into a shared helper used by
both POST and GET, and restrict the GET :name parameter to the
known SecretName enum so unrelated probing returns 404 up front.

* [AI] Simplify secrets auth guard after review

- Use existing getActiveLoginMethod() helper instead of duplicating
  the SELECT inline; drop the redundant try/catch.
- Validate the secret name against the SecretName enum before doing
  the auth-method DB query so bogus probes fail fast.
- Switch the enum membership check from hasOwnProperty.call to the
  more idiomatic in operator.
- Tighten the function-header comment to a single WHY line.
- Drop the dead else-branch from the test helper.

* [AI] Move response building back into the secrets handlers

Reshape the helper as canManageSecrets(userId) - a pure predicate over
the user. Each handler now owns its own 403 response so request/response
plumbing stays inside the route handlers.

* [AI] Undo testSecretName -> validSecretName rename

Reuse the original testSecretName / testSecretValue constants; only
the value of testSecretName changes to a real SecretName so the GET
handler's enum check accepts it.

* [AI] Add release note for #7862

* [AI] Validate POST secret name and tighten GET auth ordering

- POST /secret/ now rejects names not in the SecretName enum with 400.
- GET /secret/:name runs the admin check before the enum check so
  non-admins in OpenID mode get a uniform 403 regardless of whether
  the requested name is valid.
- Add tests for both: admin POST success in OpenID mode, and POST 400
  for unknown secret names.

---------

Co-authored-by: Claude <noreply@anthropic.com>
2026-05-16 20:59:31 +00:00
Matt FiddamanandGitHub 36e5cb17f5 fix healthcheck script (#7840)
* fix healthcheck script

* note

* test release docker image
2026-05-14 21:39:10 +00:00
Matiss Janis AboltinsGitHubClaudegithub-actions[bot] <github-actions[bot]@users.noreply.github.com>
2c9e0af3e4 Fix OpenID auth test flakiness (#7847)
* [AI] Fix flaky openid /config test from cross-worker auth race

Vitest runs sync-server test files in parallel workers that share
account.sqlite. Other files (e.g. app-account.test.js) insert 'openid'
auth rows, and auth.method is a PRIMARY KEY, so a concurrent INSERT in
app-openid.test.ts can hit UNIQUE constraint failed: auth.method.

Use INSERT OR REPLACE in the helper and clear the auth table in
beforeEach for a clean start.

* Add release notes for PR #7847

* Change category from Bugfixes to Maintenance

Fix OpenID authentication test flakiness by ensuring test isolation with INSERT OR REPLACE.

* [AI] Disable file parallelism for sync-server tests

The previous fix only patched insertOpenIdAuth in app-openid.test.ts,
but app-account.test.js's insertAuthRow helper also does plain
INSERT INTO auth ... 'openid' ... (lines 197, 203, 210, 229, 245).
With maxWorkers: 2 and a shared account.sqlite, either file's INSERT
can race the other's and hit UNIQUE constraint failed: auth.method.

Disable cross-file parallelism so test files run sequentially against
the shared DB. Within-file tests still run sequentially by default.
Test suite goes from ~20s to ~36s; trades some speed for stability.

* [AI] Revert openid test changes, reword release note

The fileParallelism: false change in vitest.config.ts already prevents
the auth.method UNIQUE-constraint race across files, so the INSERT OR
REPLACE and extra beforeEach cleanup in app-openid.test.ts are no longer
needed. Revert that file back to its original state and reword the
release note to describe the actual fix.

---------

Co-authored-by: Claude <noreply@anthropic.com>
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2026-05-14 21:30:33 +00:00
Matt FiddamanandGitHub e04924810d clean up GoCardless bank factory loading process (#7809)
* remove TLA in bank-factory

* note
2026-05-14 21:04:20 +00:00
2c7f3c7a3d [AI] Replace google-protobuf with @bufbuild/protobuf (#7535)
* [AI] crdt: typecheck test files and clean up lint issues

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* [AI] Replace google-protobuf with @bufbuild/protobuf

Swap the google-protobuf + ts-protoc-gen + protoc-gen-js toolchain for
@bufbuild/protobuf + @bufbuild/protoc-gen-es. The generator now emits a
single pure-TS sync_pb.ts (no .js sidecar, no globalThis.proto hack)
and a thin wrapper in proto/compat.ts preserves the SyncProtoBuf /
SyncRequest / etc. API so call sites stay unchanged. Removes the
loot-core CommonJS require polyfill that only existed to service
google-protobuf.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* [AI] Align @bufbuild/protobuf version ranges with installed

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* [AI] crdt: drop the SyncProtoBuf compat layer

The proto/compat.ts wrapper was introduced alongside the bufbuild
migration to avoid touching call sites. With bufbuild messages already
exposing fields as plain mutable properties, the wrapper was just
boilerplate hiding direct reads and writes — and it had drifted (e.g.
setMessagesList was called in a test but never defined).

Delete compat.ts and migrate the six call sites in loot-core and
sync-server to use @bufbuild/protobuf directly. The crdt package now
re-exports the sync_pb types/schemas and the three bufbuild runtime
helpers (create, fromBinary, toBinary) so consumers keep a single
import source.

Also switch sync-server's @actual-app/crdt dependency from the pinned
"2.1.0" to "workspace:*", matching api/loot-core — the npm pin was
pulling the stale published copy instead of the workspace source.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* [AI] CI: drive sync-server build through lage so crdt deps are built

Before: the server job ran `yarn workspace @actual-app/sync-server build`
directly, which invokes tsgo without first emitting the workspace
dependencies' declarations. That worked when sync-server pinned crdt to
the published npm version (declarations bundled in the tarball), but
with `workspace:*` it fails with TS6305 because packages/crdt/dist/*.d.ts
hasn't been built yet.

Switch the CI command to `yarn build --to=@actual-app/sync-server`.
Lage respects the `dependsOn: ['^build']` pipeline and builds
@actual-app/crdt (and the other transitive deps) before sync-server.

Using --to rather than --scope keeps the build set minimal; --scope
would also include dependents like desktop-electron.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* [AI] sync-server: build project references via tsgo -b

The build script ran plain `tsgo`, which doesn't compile referenced
projects. With @actual-app/crdt now a `workspace:*` dep (no bundled
declarations from the npm tarball), the sync-server build fails with
TS6305 because packages/crdt/dist/index.d.ts doesn't exist yet.

Switch to `tsgo -b` so the sync-server build is self-contained: it
emits crdt's declarations into packages/crdt/dist on demand. This
mirrors what the sync-server `typecheck` script already does and fixes
all callers (`build:server`, docker-edge, publish workflows, the
direct `yarn workspace @actual-app/sync-server build` invocation in
build.yml) without needing per-workflow lage orchestration.

Revert the build.yml workaround added in the previous commit.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* [AI] sync-server: build @actual-app/crdt before tsgo

The previous tsgo -b approach emitted crdt's .d.ts via the project
reference but never produced dist/index.js — tsgo respects crdt's
tsconfig which has emitDeclarationOnly: true, and the actual JS
runtime is emitted by Vite in crdt's build script. So sync-server
compiled cleanly but crashed at runtime when forked by desktop-electron
(require('@actual-app/crdt') resolved to a package whose main pointed
at a nonexistent file, surfaced in e2e as the onboarding screen never
leaving the "Configure your server" state).

Unlike packages/api (which uses Vite with noExternal: true and bundles
crdt's source inline), sync-server uses plain tsgo compilation and
keeps its deps external — so crdt must be built ahead of time and be
resolvable via node_modules at runtime.

Chain `yarn workspace @actual-app/crdt build` before tsgo so every
caller of sync-server's build (build:server, docker-edge, publish
workflows, direct invocations in CI) gets a complete crdt dist. Revert
tsgo -b back to plain tsgo since crdt's build step now emits both the
JS and the declarations.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* [AI] crdt: expose dist/ via conditional exports so Node can load it

The package's `exports` field pointed straight at `./src/index.ts`,
which works for TS tooling and bundlers (vite with noExternal, vitest)
but breaks at plain-Node runtime — Node can't execute `.ts` files and
resolves dependent `./crdt` as a directory import, failing with
ERR_UNSUPPORTED_DIR_IMPORT.

That was invisible before because sync-server pinned
`@actual-app/crdt@2.1.0` and ran against the published npm tarball
(whose `publishConfig.exports` had already been promoted to the main
`exports` by yarn pack). Switching sync-server to `workspace:*` made
the raw workspace exports win at runtime: the compiled server imported
crdt when desktop-electron forked it, Node hit the `.ts` entry, the
utility process crashed before emitting `server-started`, and the
onboarding flow stalled on "Configure your server".

Switch to the same conditional-exports pattern packages/api already
uses: types → dist/index.d.ts, development → src/index.ts (for vitest
runs that enable the `development` condition), default → dist/index.js
(Node runtime and any other consumer). `publishConfig.exports` still
collapses this to just types + default for the npm tarball.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* [AI] crdt: split exports per consumer (browser source, node dist)

Previous commit's conditional exports routed everything non-development
to ./dist/index.js. That broke the web build: rolldown runs with
conditions ['electron-renderer', 'module', 'browser', 'default'] — no
match for development, falls through to the dist entry, which isn't
built by bin/package-browser, and fails to resolve @actual-app/crdt
when bundling loot-core's server/undo.ts.

Split the entries so each consumer lands on the right artifact:

  types       → ./dist/index.d.ts   (TypeScript, project references)
  development → ./src/index.ts      (vitest — both configs include it)
  browser     → ./src/index.ts      (web rolldown bundles the source)
  node        → ./dist/index.js     (sync-server forked by Node at
                                     runtime — the failure that kicked
                                     off this whole saga)
  default     → ./src/index.ts      (fallback for bundlers like api's
                                     vite build with conditions=['api'])

Verified: node resolves to dist, yarn build:browser succeeds from a
clean crdt/, sync-server build produces both dist/index.js and
build/app.js, loot-core (552) + sync-server (386) tests pass, full
typecheck clean.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* [AI] address review feedback on crdt/sync-server

- generate-proto: add `set -euo pipefail` so a protoc failure exits the
  script non-zero instead of silently running oxfmt on whatever is in
  src/proto/ from the previous run.
- sync.proto SyncRequest: field numbers jumped from 3 to 5; declare
  `reserved 4;` so the slot can't be silently reused for a new field
  with an incompatible type. Regenerated sync_pb.ts — the reservation
  shows up in the encoded file descriptor.
- sync-simple.js: SQLite stores is_encrypted as a 0/1 integer and
  better-sqlite3 hands it back as a number, but the bufbuild
  MessageEnvelope schema types isEncrypted as bool. Coerce to boolean
  when constructing the envelope so the JS value matches the field
  type before toBinary runs.

Skipped the suggested `types` → ./src/index.ts swap in crdt's exports:
packages/api uses the same `types` → dist pattern and TypeScript's
bundler resolution already falls through when dist/*.d.ts doesn't yet
exist (verified — loot-core typecheck passes with packages/crdt/dist
removed).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* [AI] address review feedback on encoder/app-sync test

- encoder.ts: prefs.getPrefs().encryptKeyId is `string | undefined`
  (MetadataPrefs is a Partial<>). The bufbuild SyncRequestSchema's
  keyId field is a non-optional proto3 string. Current code worked by
  accident — passing undefined into `create(Schema, init)` falls back
  to the schema default '' — but relied on bufbuild's undef-handling
  and would break if someone dropped @ts-strict-ignore. Normalize to
  '' explicitly.
- app-sync.test.ts: add a short WHY comment next to
  `syncRequest.since = ''` in "returns 422 if since is not provided".
  The test's intent (missing since) only matches the handler's
  `requestPb.since || null` falsy-check because proto3 strips '' on
  the wire and decodes it back to ''. Not obvious without the comment.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* [AI] crdt: load source directly in dev, only use dist when published

Local exports point at src/index.ts so consumers (sync-server in
particular) never load a stale Vite bundle. publishConfig keeps the
dist/ mapping for npm consumers. Switched the Vite output to ESM and
added "type": "module" so the published bundle stays consistent.

Sync-server's existing extension-resolution loader is extended to
handle directory imports and is now registered at runtime via
--import ./register-loader.mjs, matching how tests already load it.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* [AI] desktop-electron: register sync-server loader on the embedded fork

The Electron app starts the sync server via utilityProcess.fork, which
bypasses sync-server's `start` script. With crdt now loaded from
source, the fork needs the same `--import register-loader.mjs` that
the standalone server uses; otherwise it crashes on the extensionless
`from './crdt'` directory import. Adds the loader files to
sync-server's published `files` so they actually ship with the
packaged app.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* [AI] sync-server: bootstrap entry that registers the loader for utilityProcess

Electron's utilityProcess.fork accepts execArgv but silently ignores
--import (verified with a minimal repro: the flag shows up in
process.execArgv but the preload module never executes), so the
previous attempt was a no-op and the embedded sync-server still
crashed on crdt's ESM directory imports. Add packages/sync-server/start.mjs
that statically imports register-loader.mjs and then dynamic-imports
build/app.js, so the loader is in place before the app's module graph
resolves. desktop-electron now points utilityProcess.fork at start.mjs
and drops the ineffective --import flag.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-12 17:55:52 +00:00
50feba1afb [AI] Fix flaky API test timeouts and use sync file write in tests (#7806)
* [AI] Fix flaky upload-user-file test

The "uploads and updates an existing file successfully" test wrote the
old file content using the async callback form of fs.writeFile without
awaiting it. That write could land after the upload endpoint had already
written the new content, leaving the file with stale content and failing
the assertion. Use fs.writeFileSync so the setup completes before the
request is sent.

* [AI] Increase api test timeouts to fix flaky budget-load test

methods.test.ts loads a budget file and runs all DB migrations in each
test/hook. On busy CI runners this regularly approaches the default 5s
limit, and when it exceeds it the in-flight loadBudget keeps running after
teardown closes the database, producing a cascade of unhandled rejections
("database connection is not open", "no such table: v_schedules",
"Cannot read properties of undefined (reading 'timestamp')") that fail the
suite. Bump testTimeout/hookTimeout to 20s for the api package.

* [AI] Add release note for flaky test fixes

---------

Co-authored-by: Claude <noreply@anthropic.com>
2026-05-11 22:07:25 +00:00
Matiss Janis AboltinsGitHubClaude Opus 4.7github-actions[bot] <github-actions[bot]@users.noreply.github.com>Cursor AgentMatiss Janis Aboltins
a95c0ad9b0 [AI] sync server changes; crdt & et al (#7702)
* [AI] Load @actual-app/crdt from source in dev, only bundle for publish

@actual-app/crdt's local exports now point at src/index.ts so consumers
(sync-server, loot-core, desktop-client) never see a stale Vite bundle.
publishConfig keeps the dist/ mapping for npm consumers. crdt's
tsconfig switches to bundler module resolution to match the rest of
the workspace (no extensions in source imports).

Sync-server's existing extension-resolution loader is extended to also
handle directory-index imports (./crdt → ./crdt/index.ts), and the
standalone `start` / `start-monitor` scripts now invoke Node with
--import ./register-loader.mjs so the loader is in place before crdt's
source resolves.

Electron's utilityProcess.fork accepts execArgv but doesn't actually
preload --import modules, so a new packages/sync-server/start.mjs
bootstrap entry registers the loader imperatively and then dynamic-
imports build/app.js. desktop-electron's startSyncServer() points the
fork at start.mjs. sync-server's "files" array now ships start.mjs,
register-loader.mjs and loader.mjs so packaged Electron / npm
consumers actually receive them.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* Add release notes for PR #7702

* [AI] Restructure sync-server to build with Vite

Replace the hand-rolled tsgo + add-import-extensions + copy-static-assets
+ runtime loader pipeline with a single Vite SSR build. Bundles every
entry (app, bin/actual-server, scripts/*) and inlines @actual-app/crdt
source so Node never has to resolve TS at runtime — the
MODULE_TYPELESS_PACKAGE_JSON warning that surfaced via crdt's source
exports is gone. Migrations and bank handlers move from readdir-based
dynamic imports to import.meta.glob; messages.sql becomes a ?raw import.

Drop loader.mjs, register-loader.mjs, start.mjs, and
bin/add-import-extensions.mjs. Electron's startSyncServer() forks
build/app.js directly. publishConfig.imports goes away (subpath imports
are resolved at build time and don't appear in the bundle).

In dev (start:server-dev) sync-server proxies to Vite, so loosen the CSP
to allow Vite's inline preamble script and HMR websocket — production
CSP is unchanged. desktop-client skips registerSW() in dev (and disables
vite-plugin-pwa's devOptions) so stale cached assets don't override
edits between page loads.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* [AI] Address review feedback

- sync-server CSP: drop 'unsafe-eval' from the production script-src;
  the bundle has no genuine eval/new Function usage (only a defensive
  branch in setimmediate's polyfill that's never hit). Keep it on the
  dev branch where Vite's HMR runtime relies on it. Add a comment so
  it's obvious which branch needs it and why.
- bank-factory: widen the loader glob to ./banks/*_*.{ts,js} so
  TypeScript handlers are discovered too, mirroring migrations.ts.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* [AI] Restore 'unsafe-eval' in production CSP for Electron

The Electron app needs `'unsafe-eval'` at runtime, so revert the dev-only
restriction and keep `'unsafe-eval'` in both branches. Comment updated to
record the actual reason instead of marking it as removable.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* [AI] Revert bank-factory glob change

Widening the glob to ./banks/*_*.{ts,js} broke the desktop e2e tests in
CI even though every current handler is .js and the brace expansion
matches no .ts files locally. Reverting to ./banks/*_*.js — the change
had no behavioural benefit since there are no TS handlers, so the
nitpick isn't worth chasing.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* [AI] Strip CSP comment to restore identical state to 9513c1e16

The desktop e2e has been failing despite my prior commits being a strict
revert (only difference was a 2-line comment, which can't change runtime).
Removing even the comment so the branch matches 9513c1e16's relevant
files exactly, to isolate whether the failure is from the master merge
or from CI-environment drift.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* [AI] Make rebuild-electron actually rebuild better-sqlite3

PR #7712 simplified rebuild-electron to just `electron-rebuild -f -o
better-sqlite3,bcrypt` from the repo root. Two problems with that:

  1. Without `-m`, electron-rebuild scans the root workspace's package.json
     for native deps. better-sqlite3 isn't a direct root dep — it lives
     under packages/sync-server/ — so the scan returns no candidates and
     the rebuild silently no-ops.
  2. Without --build-from-source, electron-rebuild defers to
     prebuild-install, which downloads a stale prebuilt binary keyed off
     better-sqlite3's package.json (ABI 127) instead of recompiling
     against Electron 39's bundled Node ABI 140. The download succeeds
     and "Rebuild Complete" prints, but the resulting `better_sqlite3.node`
     can't `dlopen` inside Electron's utility process — sync-server
     crashes immediately on db init, the renderer's startSyncServer IPC
     never resolves, and the e2e test hangs on "Configure your server".

Point -m at packages/desktop-electron (which transitively pulls in
better-sqlite3 and bcrypt via @actual-app/sync-server) and force a real
compile via --build-from-source. Verified locally: better-sqlite3
rebuilds to darwin-arm64-140 and the desktop e2e onboarding test passes
in 6s instead of hanging for 60s.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* [AI] Restore CSP unsafe-eval comment

Bring back the explanatory comment that was stripped diagnostically in
99682268c. Now that the desktop e2e regression is traced to
rebuild-electron and not to anything in this branch, we can keep the
documentation noting why 'unsafe-eval' is retained in both CSP branches.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* [AI] Restore bank-factory glob to ./banks/*_*.{ts,js}

Re-apply the glob widening originally added in 145868f9d. It was
reverted in 531b1a191 because the desktop e2e was failing — that
failure is now traced to the rebuild-electron breakage (fixed in
6e8ac0784), not to this glob. Mirroring migrations.ts so future TS
bank handlers are picked up.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* [AI] Fix applyAppUpdate hanging in dev mode

In dev mode browser-preload's updateSW was () => undefined, so
applyAppUpdate() — which calls updateSW() and then awaits a
deliberately never-resolving promise (waiting for the SW-driven page
reload) — hung the renderer instead of refreshing. In prod the page
is replaced by the new service worker, so the never-resolving await is
fine. The dev path now triggers a plain window.location.reload() so
the page reloads and the never-settling await is irrelevant, matching
prod's effective behaviour.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* [AI] Revert rebuild-electron to master version

* Revert "[AI] Revert rebuild-electron to master version"

This reverts commit 4b6baab79f.

---------

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
Co-authored-by: Cursor Agent <cursoragent@cursor.com>
Co-authored-by: Matiss Janis Aboltins <MatissJanis@users.noreply.github.com>
2026-05-11 17:40:42 +00:00
0fd510a1d4 Integrate Enable Banking as a bank sync provider (#7345)
* Integrate Enable Banking as bank sync provider

Rewrite Enable Banking modal to match GoCardless pattern

Resolve Enable Banking bugs and improve auth flow

* [AI] Address code review feedback for Enable Banking integration

Bug fixes:
- Fix double-negative for DBIT transaction amounts (e.g. '--25.99')
- Fix payeeName counterparty mapping (CRDT→debtor, DBIT→creditor)
- Add missing state validation in EnableBankingCallback and /auth_callback
- Fix stuck loading state in useEnableBankingStatus with try/catch/finally
- Make session-expiry error matching case-insensitive
- Prefer CLAV balance type for startingBalance in /transactions route
- Guard setTimeout in post/del/patch when timeout is null
- Distinguish abort from network failure in post() catch

Credential handling:
- Add validateCredentials() to validate before persisting secrets
- Refactor client to use enablebanking-configure instead of manual secret-set
- Distinguish null (loading) from false (not configured) in setup checks

Poll-auth robustness:
- Add unique waiter IDs to prevent superseded waiter cleanup race
- Always cache results in completedAuths for retry resilience
- Add client disconnect cleanup via res.on('close')
- Cancel poll when Enable Banking modal closes via AbortController
- Prevent concurrent poll controller race with local reference check

Code quality:
- Extract buildSessionResult() to deduplicate auth_callback/complete-auth
- Add enabled parameter to useEnableBankingStatus to skip unused requests
- Add re-entrancy guard on onJump, reset bank on country change
- Refetch bank list after Enable Banking setup completes
- Type enableBankingConfigure config, make state required in completeAuth
- Add AbortError→TIMED_OUT test, fix startAuth test assertion
- Add afterAll vi.unstubAllGlobals() for test cleanup
- Add explanatory comments for bank-per-account model and in-memory maps

* [AI] Fix missing patterns in Enable Banking integration

- Add SyncServerEnableBankingAccount to ExternalAccount union and
  getInstitutionName parameter type in SelectLinkedAccountsModal
- Use BankSyncProviders type in mobile BankSyncAccountsList instead of
  hardcoded union missing enableBanking
- Add getSecretsError handling to EnableBankingInitialiseModal for
  proper auth/permission error messages
- Replace hardcoded #666 color with theme.pageTextSubdued
- Wrap onConnectEnableBanking in try/catch with error notification and
  init modal re-open, matching SimpleFin/PluggyAI pattern
- Translate hardcoded error string in enablebanking.ts
- Add 60s timeout to downloadEnableBankingTransactions matching PluggyAI
- Revert out-of-scope changes to del()/patch() in post.ts
- Revert shared starting balance dedup logic back to master pattern

* Forward PSU headers to Enable Banking API

* Fix Enable Banking re-auth dispatch

* Respect ASPSP maximum_consent_validity when starting Enable Banking auth

* Fix missing types for module jws

* Add upcoming release notes

* Fix format

Expected "sign" (value-import) to come before "Algorithm"

* Fix code review findings on Enable Banking integration

* [AI] Disable Enable Banking button while status is loading

* typo

* [AI] Migrate enable-banking files to subpath imports

Update all enable-banking files to use # subpath imports and
@actual-app/core paths, matching the migration done in master.
Add #enablebanking entry to desktop-client package.json imports map.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* [AI] Add #app-enablebanking subpath imports to sync-server package.json

Register enablebanking service, utils, and root entries in both
the imports and publishConfig.imports maps.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* Add jws to dependencies

* [AI] Harden Enable Banking OAuth callback handoff

Enforce exact OAuth state round-trip in the Enable Banking callback so
mismatched/missing state values no longer silently complete the flow.
Replace unsafe `as`/`!` assertions in the auth handoff with typed
locals so the callback path stays sound under strict TypeScript.

* [AI] Tighten Enable Banking type safety

Make the Enable Banking external-msg modal strict-ts compatible,
annotate the id type in linkEnableBankingAccount, derive
AccountSyncSource from a single SYNC_PROVIDERS list, and annotate the
return type of getJWTBody. No behaviour change.

* [AI] Fix Enable Banking poll lifecycle and abort handling

Make the popup-driven auth poll cancellable and isolated:

- Allow the popup retry path to abort the in-flight poll instead of
  leaving it hanging on the previous attempt.
- Clear the Enable Banking stateRef when the retry attempt finishes so
  a new attempt starts from a clean state.
- Start useEnableBankingStatus in loading state until the first fetch
  resolves so the UI doesn't briefly flash "not connected".
- Cancel only the requested poll, not every in-flight Enable Banking
  poll, so unrelated link attempts aren't affected.
- Skip writing the poll response when the client has already
  disconnected, with a regression test covering the disconnect path.

* [AI] Tighten Enable Banking client/test plumbing

Misc code-quality improvements with no behaviour change:

- Parallelize Enable Banking secret reset calls so wiping multiple
  secrets doesn't serialize the request chain.
- Use absolute imports in the enable-banking client module to match the
  rest of desktop-client.
- Document externalSignal usage in the post helper.
- Tighten Enable Banking test fixtures with `satisfies` and dynamic
  dates so they stop drifting when the real "now" moves.

* [AI] Fix Enable Banking initial-balance and post-link bookkeeping

Apply the standard post-sync bookkeeping when linking an Enable Banking
account so the new account picks up the same starting-balance
treatment as other bank-sync providers, and skip pending transactions
when computing the initial balance so the figure isn't inflated by
transactions that haven't cleared yet.

* [AI] Refine Enable Banking error model and bank-sync surface

Carry the human-readable Enable Banking message in
EnableBankingError.error_type and the machine-friendly identifier in
error_code, then map error_code to a bank-sync category in the
/transactions wire format so AccountSyncCheck can match on the same
categories as other providers.

* [AI] Improve Enable Banking bank-sync field mapping

Bring the Enable Banking transaction normalizer in line with how other
bank-sync providers feed the field mapper:

- Strip SEPA structured prefixes from remittance text so notes/payee
  display the human-meaningful portion instead of the SEPA boilerplate.
- Return the notes field and spread the raw transaction so downstream
  field mapping can reach the full payload.
- Expose Enable Banking raw fields in the bank-sync field mapper UI so
  users can map any underlying property, not just the curated subset.

* [AI] Use req.ip for Enable Banking PSU header so trust-proxy whitelist applies

* [AI] Address Enable Banking CodeRabbit pass-3 follow-ups

Three small fixes from the latest CodeRabbit re-review:

- Guard the aspsps fetch in EnableBankingExternalMsgModal against stale
  responses. Switching countries quickly could let an earlier in-flight
  request overwrite the newer selection's bank list. Added a cleanup
  flag in the useEffect so only the latest response updates state.
- Clear `enablebanking_auth_state` from localStorage when the auth flow
  exits, but only if the stored value still matches this attempt's
  state, so a concurrent retry can't wipe a newer session. Wrapping
  the poll in try/finally covers every return path (success, timeout,
  abort, body-level error).
- Use `Boolean(trans.booked)` in the Enable Banking initial-balance
  predicate to match `normalizeBankSyncTransactions`. The Enable
  Banking normalizer always sets `booked` to a boolean today, so this
  is defensive rather than a live bug, but keeping the two predicates
  aligned avoids surprises if the upstream shape ever loosens.

* [AI] Address Enable Banking CodeRabbit pass-3 follow-ups (round 2)

Two more findings from the latest CodeRabbit pass:

- Guard onJump against stale-retry completions. Token each call with a
  monotonic jumpIdRef counter and gate every post-await write
  (setError/setWaiting after onMoveExternal, the second setWaiting,
  and the finally-block ref reset) on `myJumpId === jumpIdRef.current`.
  Without this, a retry click while the previous poll was still
  unwinding could surface the older call's error in the newer
  attempt's UI and clear stateRef/isJumpingRef out from under it,
  leaving the new poll un-cancellable.
- Translate the (beta) suffix on Enable Banking ASPSP names so
  non-English locales don't surface a hardcoded English token in the
  bank list. The existing `actual/no-untranslated-strings` rule misses
  this case (regex requires a leading uppercase, and template-literal
  interpolations aren't visited as standalone strings).

* [AI] Use SEPA prefix allowlist instead of catch-all regex

The previous `^[A-Z]{3,}\+` regex would incorrectly strip merchant
tokens like `BMW+`, `USB+`, or `COVID+` from the start of a remittance
line. Replaced it with an explicit allowlist of known SEPA / ISO 20022
prefixes and added a regression test covering the false-positive case.

* [AI] Use uuidv4 instead of crypto.randomUUID in Enable Banking

Aligns with master's revert in #7734 (crypto.randomUUID back to uuid
library). Two stray spots remained in Enable Banking code: the
link-account flow in loot-core/server/accounts/app.ts and the OAuth
state token in sync-server/app-enablebanking.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Matiss Janis Aboltins <matiss@mja.lv>
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-05-11 14:05:30 +00:00
18c704b3ba [AI] Sync server: harden CORS proxy method validation (#7788)
* [AI] Sync server: harden CORS proxy method validation

The CORS proxy validated `method` against a fallback-normalized value but
forwarded the raw client-supplied value to fetch(), letting a non-string
input (e.g. ["POST"]) bypass the GET/HEAD allowlist via undici's String()
coercion. Reject non-string method, pass the validated normalized method
to fetch(), and drop the unreachable body-forwarding branch.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* [AI] Polish release notes wording

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* Rename 7787.md to 7788.md

---------

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-10 16:11:40 +00:00
dependabot[bot]GitHubdependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>Cursor AgentMatiss Janis Aboltins
db38565524 Bump uuid from 13.0.2 to 14.0.0 (#7739)
* Bump uuid from 13.0.2 to 14.0.0

Bumps [uuid](https://github.com/uuidjs/uuid) from 13.0.2 to 14.0.0.
- [Release notes](https://github.com/uuidjs/uuid/releases)
- [Changelog](https://github.com/uuidjs/uuid/blob/main/CHANGELOG.md)
- [Commits](https://github.com/uuidjs/uuid/compare/v13.0.2...v14.0.0)

---
updated-dependencies:
- dependency-name: uuid
  dependency-version: 14.0.0
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>

* [AI] Add engines field to sync-server package.json for Node.js >=22 requirement

Co-authored-by: Matiss Janis Aboltins <MatissJanis@users.noreply.github.com>

---------

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Cursor Agent <cursoragent@cursor.com>
Co-authored-by: Matiss Janis Aboltins <MatissJanis@users.noreply.github.com>
2026-05-08 20:40:07 +00:00
Matiss Janis AboltinsandGitHub 345c99be4d [AI] Bump workspace packages to 26.5.2 and document 26.5.2 in release notes (#7756) 2026-05-08 19:30:10 +00:00
Matiss Janis AboltinsandGitHub bc08ed97e9 [AI] 🔖 Release 26.5.1 (#7745) 2026-05-08 17:11:46 +00:00
Matiss Janis AboltinsGitHubClaudegithub-actions[bot] <github-actions[bot]@users.noreply.github.com>Matiss Janis Aboltins
852b95524b [AI] Revert crypto.randomUUID back to uuid library (#7734)
* [AI] Revert crypto.randomUUID back to uuid library

Partial revert of #7529. Restores the `uuid` package dependency in
api, crdt, desktop-client, loot-core, and sync-server, swapping every
`crypto.randomUUID()` call introduced by that PR back to `uuidv4()`
(and the `uuid()` alias in RuleEditor.tsx and ruleUtils.ts where it
was previously used). The lint rule, docs entry, and `vi.mock('uuid')`
test setup are restored as well. The `fs-extra` removals in
desktop-electron from the same PR are left in place.

https://claude.ai/code/session_01KTg1g416Jdjf5feGke8MQw

* Add release notes for PR #7734

* [check-spelling] Update metadata

Update for https://github.com/actualbudget/actual/actions/runs/25480733101/attempts/1
Accepted in https://github.com/actualbudget/actual/pull/7734#issuecomment-4394811498

Signed-off-by: check-spelling-bot <check-spelling-bot@users.noreply.github.com>
on-behalf-of: @check-spelling <check-spelling-bot@check-spelling.dev>

* [AI] Use the uuidv4 alias in RuleEditor and ruleUtils

The previous commit preserved the `v4 as uuid` alias in these two files
to match their pre-#7529 state, but the project convention (and lint
rule message) is `v4 as uuidv4`. CodeRabbit flagged the inconsistency,
so normalize the alias and call sites in both files.

https://claude.ai/code/session_01KTg1g416Jdjf5feGke8MQw

* [AI] Pin uuid to ^11.1.0 to fix Electron e2e

uuid v13 is ESM-only (no CJS entry, only an exports map with `node` and
`default` conditions both pointing to ESM files). The Electron backend is
bundled as CJS by `loot-core/vite.desktop.config.mts` and loaded via a
dynamic `await import(process.env.lootCoreScript!)` in the
desktop-electron utilityProcess; that pipeline appears to fall over on
the ESM-to-CJS transform of uuid v13 in Vite 8 / rolldown, which makes
the Functional Desktop App e2e job fail consistently while every other
check (web e2e, VRT, unit tests, lint, typecheck) passes.

uuid v11 still ships `dist/cjs/index.js`, so pinning each workspace's
uuid range to ^11.1.0 sidesteps the resolution path entirely. The API
is unchanged (`v4` is still the same export), so no source-code changes
are needed.

https://claude.ai/code/session_01KTg1g416Jdjf5feGke8MQw

* [AI] Capture Electron stdout/stderr in desktop e2e fixture (TEMP DEBUG)

Pipe the Electron main+utility process stdout/stderr into both the
playwright runner stderr and an electron.log file inside the test's
output directory. This makes the actual backend error visible in the
Functional Desktop App job output and in the desktop-app-test-results
artifact.

Will be reverted once the failure cause is identified.

https://claude.ai/code/session_01KTg1g416Jdjf5feGke8MQw

* Revert "[AI] Capture Electron stdout/stderr in desktop e2e fixture (TEMP DEBUG)"

This reverts commit 4cb5148859.

* [AI] Fix rebuild-electron and bump uuid back to ^13.0.0

The Functional Desktop App e2e job had been failing with
ERR_DLOPEN_FAILED on better-sqlite3 (NODE_MODULE_VERSION 127 vs 140),
which surfaced because this PR's yarn.lock change invalidated the
GitHub Actions node_modules cache. With a fresh install,
rebuild-electron is responsible for compiling better-sqlite3 and
bcrypt against Electron's ABI — but since #7712 the script has been
running from the repo root, where neither module is a direct
dependency, so electron-rebuild silently exits as a no-op.

Restore the `-m ./packages/desktop-electron` scoping that #7712
removed, so the rebuild actually finds and rebuilds the modules.
This fix is technically out of scope for this PR but it blocks any
PR that touches yarn.lock.

Also revert the `^11.1.0` pin from the previous commit back to
`^13.0.0`. The pin was based on a wrong hypothesis (that uuid v13's
ESM-only packaging was breaking the bundle); now that the real
cause is identified, there is no reason to deviate from the
pre-#7529 version.

https://claude.ai/code/session_01KTg1g416Jdjf5feGke8MQw

---------

Signed-off-by: check-spelling-bot <check-spelling-bot@users.noreply.github.com>
Co-authored-by: Claude <noreply@anthropic.com>
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
Co-authored-by: Matiss Janis Aboltins <MatissJanis@users.noreply.github.com>
2026-05-07 19:18:47 +00:00
d787d0ce43 fix: only count failed attempts against auth rate limit (#7707)
* fix: only count failed attempts against auth rate limit

Add skipSuccessfulRequests: true to authRateLimiter so that successful
logins do not consume quota. This fixes breakage for API clients
(actual-cli, actual-mcp, custom scripts) that re-authenticate per
operation — they always provide the correct password, so they should
never be rate-limited.

Brute-force attackers generate repeated failures and still hit the wall.

Fixes #7706

* Update upcoming-release-notes/7706.md

Co-authored-by: Matt Fiddaman <github@m.fiddaman.uk>

* fix: rename release note to match PR number

---------

Co-authored-by: Matt Fiddaman <github@m.fiddaman.uk>
2026-05-04 22:27:18 +00:00
6c2c96e826 🔖 (26.5.0) (#7621)
* 🔖 (26.5.0)

* fix release note generation script (#7635)

* fix release note generation script

* note

* fix cherrypicked commits not being respected and lint race in release note generation workflow (#7640)

* fix cherrypicked commits not being respected and lint race

* note

* coderabbit suggestions

* fix lint

* make double restore possibility safe

* fix lint (#7643)

* Generate release notes for v26.5.0

* add release note highlights

* Fix Sankey income bug, when payee it not set (#7632)

* Ensure income categories are shown correct, even if payee is not set

* Add release note

* Generate release notes for v26.5.0

* increase test coverage for budget templates (#7620)

* [AI] cover existing template engine logic with regression tests

Adds tests for goal template behavior that predates this PR so the
suite can be cherry-picked onto master to confirm no regressions. No
production code changes.

Covers:
- init() validation: schedule names, by/schedule priority match, past
  by-target with and without annual/repeat, percentage source not
  found, special source aliases, duplicate limit/spend/goal
  directives, weekly limit missing start date, invalid limit period,
  unrecognized periodic period
- runRemainder cap clamping and hideDecimal fraction removal
- Income-category branch in runTemplatesForPriority
- getLimitExcess against an aggregate weekly cap
- Past by-target rolling forward via the annual period
- runSchedule full=true (no sinking accumulation), percent and fixed
  adjustments, completed-schedule filtering, past-date error for
  non-repeating schedules, monthly/weekly/daily sinking contribution
  branches when interval exceeds the pay-month-of cap, surplus
  absorption when last-month balance exceeds the target, and
  tracking-budget mode forcing all schedules pay-month-of
- applyMultipleCategoryTemplates orchestration: per-category writes,
  cross-category priority clamping when funds run out, error
  notification path
- applyTemplate force=false skipping already-budgeted categories

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* note

---------

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* fix infinite loop when remainder is impossible to solve (#7623)

* fix infinite loop when remainder is impossible to solve

* note

* Generate release notes for v26.5.0

* Update author

Updated author information in the release notes.

* Fix shared worker resumption after tab suspend (#7656)

* [AI] Fix SharedWorker tab resume recovery

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* [AI] Fix SharedWorker reload readiness

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* Add release notes

* Update packages/desktop-client/src/shared-browser-server-core.ts

Co-authored-by: Matiss Janis Aboltins <matiss@mja.lv>

---------

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Matiss Janis Aboltins <matiss@mja.lv>

* Update docs release date

* Empty commit to bump CI

* Generate release notes for v26.5.0

* Revert "Generate release notes for v26.5.0"

This reverts commit b42c48bed5.

---------

Co-authored-by: github-merge-queue <118344674+github-merge-queue@users.noreply.github.com>
Co-authored-by: Matt Fiddaman <github@m.fiddaman.uk>
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: Emil Tveden Bjerglund <emilbp@gmail.com>
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Co-authored-by: Julian Dominguez-Schatz <julian.dominguezschatz@gmail.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-05-03 17:41:17 +00:00
Julian Dominguez-SchatzandGitHub da1d0a94b9 Migrate file service to TypeScript (#7606)
* Migrate file service to TypeScript

* Add release notes

* Rabbit

* Stricter types
2026-04-24 22:50:43 +00:00
Julian Dominguez-SchatzandGitHub 227c995155 Disallow reconfiguring OpenID after initialization (#7608)
* Disallow reconfiguring OpenID after initialization

* Add release notes
2026-04-24 15:12:01 +00:00
7501674613 [AI] Fix Docker build for workspace:* dependencies (#7564)
* [AI] Fix Docker build for workspace:* dependencies

Since @actual-app/crdt became a workspace:* dep, `yarn workspaces focus
--production` creates relative symlinks in node_modules that dangle when
only node_modules is copied into the prod image, breaking local Docker
builds with ERR_MODULE_NOT_FOUND: @actual-app/crdt.

Dereference yarn's workspace symlinks in the builder stage with `cp -RL`
so the prod stage can copy a self-contained node_modules without needing
to enumerate which workspace:* deps exist. Adding a new workspace:* dep
now requires zero Dockerfile changes.

Also move the sync-server .dockerignore to the repo root (and drop stray
local node_modules / .git / .yarn caches from the build context), since
docker builds use the repo root as context — the old sync-server-level
file was no longer being applied.

Fixes #7561.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* [AI] Strip dev-only dirs from dereferenced workspace packages

The generic `cp -RL` step copies full workspace package trees into the
image (src/, e2e/, tests, build-stats, etc.). Remove them after the
dereference — they're not needed at runtime, and skipping them recovers
~67MB from the final image on both alpine and ubuntu variants.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* [AI] Rephrase 7564 release note to be user-facing

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-22 19:20:51 +00:00
Matt FiddamanandGitHub 9d91da77ec move from tsgo dev preview to beta (#7587)
* move from tsgo dev preview to beta

* note
2026-04-22 15:22:14 +00:00
Matt FiddamanandGitHub 2f49c5c400 add repository details to package.json files (#7578)
* add package URLs

* note
2026-04-21 17:40:11 +00:00
Matiss Janis AboltinsandGitHub 75da8f1851 [AI] fix: ensure crdt builds before loot-core is packed (#7565)
The `Publish nightly npm packages` workflow started failing at the
"Pack the core package" step with:

    Cannot find module '@actual-app/crdt' or its corresponding type declarations.

PR #7541 switched `@actual-app/crdt`'s package.json to conditional
exports (`types` → `./dist/index.d.ts`). `yarn pack` for
`@actual-app/core` triggers a prepack that runs `tsgo -b`, which now
resolves `@actual-app/crdt` via the `types` condition and expects
`packages/crdt/dist/index.d.ts`. Nothing was building crdt first
because loot-core's tsconfig didn't declare it as a project
reference.

Fix: declare the project reference so `tsgo -b` walks the graph and
builds crdt before loot-core. Sibling packages already do this.

Also adopt `@monorepo-utils/workspaces-to-typescript-project-references`
to keep each package's tsconfig `references` in sync with its
`workspace:*` deps, and wire it into a new `yarn check:tsconfig-references`
step in the `check` CI job plus lint-staged. Running the tool added
`../desktop-client` references to sync-server and desktop-electron
(both declare `@actual-app/web` as a workspace dep even though they
only use it at runtime via `require.resolve`); the extra references
are harmless — in CI the corresponding build is already cached by
earlier steps.

https://claude.ai/code/session_01AA2gEMqX24GWeq5BovNmaz
2026-04-20 22:07:27 +00:00
9fb6876f3b [AI] sync-server: use workspace reference for @actual-app/crdt (#7541)
* [AI] sync-server: use workspace reference for @actual-app/crdt

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* Update build script in sync-server package to use TypeScript's build mode

* Package electron

* [AI] crdt: add conditional exports so Node can load the built bundle

Before this change the root exports entry pointed at `./src/index.ts`, so
any pure-Node consumer (notably the sync server that Electron forks as a
utility process) failed to import `@actual-app/crdt` — Node can't execute
TypeScript source directly. Sync-server had been masking this by pulling
`@actual-app/crdt@npm:2.1.0` where `publishConfig.exports` resolves to
`./dist/index.js`; once sync-server switched to `workspace:*`, the
Functional Desktop App CI job timed out waiting for the sync server to
boot.

Switch to conditional exports in the same shape `@actual-app/api` already
uses:

- `types` → `./dist/index.d.ts` for TypeScript tooling
- `development` → `./src/index.ts` for Vite/Vitest (HMR, fast feedback)
- `default` → `./dist/index.js` for Node runtime

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-18 15:27:34 +00:00
Matt FiddamanandGitHub a4e401bc8b fix build error with typescript v6 (#7524)
* fix tsconfig error

* note

* fix strict mode violation

* fix another type issue
2026-04-17 20:52:44 +00:00
Matt FiddamanandGitHub 711939f71c replace uuid and fs-extra with builtins (#7529)
* fs-extra

* uuid

* note
2026-04-16 20:42:27 +00:00
Matt FiddamanandGitHub 8486dca33a clean up more unused dependencies (#7528)
* remove unused deps

* note

* remove babel

* fix lint
2026-04-16 20:23:13 +00:00
Matt FiddamanGitHubCopilot Autofix powered by AI <223894421+github-code-quality[bot]@users.noreply.github.com>
7a4b43e7a4 fix some more GitHub code quality issues (#7520)
* Apply suggested fix to packages/desktop-client/src/components/modals/EditFieldModal.tsx from Copilot Autofix

Co-authored-by: Copilot Autofix powered by AI <223894421+github-code-quality[bot]@users.noreply.github.com>

* Apply suggested fix to packages/desktop-client/src/components/modals/EditFieldModal.tsx from Copilot Autofix

Co-authored-by: Copilot Autofix powered by AI <223894421+github-code-quality[bot]@users.noreply.github.com>

* note

* fix typo in note

* remove useless conditions

---------

Co-authored-by: Copilot Autofix powered by AI <223894421+github-code-quality[bot]@users.noreply.github.com>
2026-04-16 17:07:22 +00:00
Matt FiddamanandGitHub 8c47374b9d ⬆️ mid-month dependency bump (#7506)
* typescript (^5.9.3 -> ^6.0.2)

* eslint-plugin-perfectionist (^5.6.0 → ^5.8.0)

* @types/node (^22.19.15 → ^22.19.17)

* @typescript/native-preview (^7.0.0-dev.20260309.1 → ^7.0.0-dev.20260404.1)

* eslint (^9.39.3 → ^9.39.4)

* lage (^2.14.19 → ^2.15.5)

* lint-staged (^16.3.2 → ^16.4.0)

* minimatch (^10.2.4 → ^10.2.5)

* vitest (^4.1.0 → ^4.1.2)

* better-sqlite3 (^12.6.2 → ^12.8.0)

* commander (^13.0.0 → ^13.1.0)

* cosmiconfig (^9.0.0 → ^9.0.1)

* @chromatic-com/storybook (^5.0.1 → ^5.1.1)

* @storybook/addon-a11y (^10.2.16 → ^10.3.4)

* @storybook/addon-docs (^10.2.16 → ^10.3.4)

* @storybook/react-vite (^10.2.16 → ^10.3.4)

* eslint-plugin-storybook (^10.2.16 → ^10.3.4)

* storybook (^10.2.16 → ^10.3.4)

* @codemirror/language (^6.12.2 → ^6.12.3)

* @react-aria/interactions (^3.27.0 → ^3.27.1)

* @swc/core (^1.15.18 → ^1.15.24)

* @swc/helpers (^0.5.19 → ^0.5.21)

* @tanstack/react-query (^5.90.21 → ^5.96.2)

* @uiw/react-codemirror (^4.25.7 → ^4.25.9)

* @vitejs/plugin-basic-ssl (^2.2.0 → ^2.3.0)

* i18next (^25.8.14 → ^25.10.10)

* lru-cache (^11.2.6 → ^11.2.7)

* react-grid-layout (^2.2.2 → ^2.2.3)

* react-i18next (^16.5.6 → ^16.6.6)

* rolldown (^1.0.0-rc.12 → ^1.0.0-rc.13)

* sass (^1.97.3 → ^1.99.0)

* adm-zip (^0.5.16 → ^0.5.17)

* csv-parse (^6.1.0 → ^6.2.1)

* csv-stringify (^6.6.0 → ^6.7.0)

* jest-diff (^30.2.0 → ^30.3.0)

* express-rate-limit (^8.3.0 → ^8.3.2)

* upgrade yarn to 4.13.0

* react-aria-components (^1.15.1 → ^1.16.0)

* @vitejs/plugin-react (^6.0.0 → ^6.0.1)

* @codemirror/state (^6.5.4 → ^6.6.0), @codemirror/view (^6.38.7 → ^6.41.0)

* react-aria (^3.46.0 → ^3.47.0)

* react-error-boundary (^6.0.3 → ^6.1.1)

* recharts (^3.7.0 → ^3.8.1)

* fast-check (4.5.3 → ^4.6.0)

* rollup-plugin-visualizer (^6.0.11 → ^7.0.1)

* commander (^13.1.0 → ^14.0.3)

* note

* coderabbit feedback, and a test for good measure

* typescript (^5.9.3 -> ^6.0.2)

* @playwright/test (1.58.2 -> 1.59.1)

* yarn dedupe
2026-04-15 17:05:26 +00:00
410658009e [AI] Fix sync-server build not resolving subpath imports (#7478)
* [AI] Fix sync-server build not resolving subpath imports

The add-import-extensions build script only handled relative imports
(./  ../), leaving #-prefixed subpath imports unresolved in the build
output. At runtime Node.js resolved them via package.json's imports
map back to source files, which have extensionless imports that fail
in ESM.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* [AI] Add release notes for sync-server subpath imports fix

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* [AI] Simplify subpath import resolution using publishConfig.imports

Use publishConfig.imports which already has ./build/src/ paths with .js
extensions, eliminating manual src->build and .ts->.js conversions.
Also sort wildcard patterns by specificity and extract shared helper.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* [AI] Use replaceAll for wildcard substitution to satisfy CodeQL

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-12 05:36:55 +00:00
65b154151f [AI] Enable subpath imports across all packages (#7462)
* [AI] Enable subpath imports across all packages

Generalize the prefer-subpath-imports ESLint rule to work with any
package (not just loot-core) and enable it globally. Add subpath import
mappings to cli, component-library, and sync-server package.json files.
Auto-fix all backtracked relative imports to use #-prefixed subpath
imports.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* [AI] Add release notes for #7462

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* [AI] Fix mock specifiers in accounts.test.ts to use aliased imports

Co-authored-by: Matiss Janis Aboltins <MatissJanis@users.noreply.github.com>

* [AI] Fix mock specifiers in query.test.ts to use aliased imports

Co-authored-by: Matiss Janis Aboltins <MatissJanis@users.noreply.github.com>

* [AI] Fix ESLint rule to properly validate src/ directory paths

Co-authored-by: Matiss Janis Aboltins <MatissJanis@users.noreply.github.com>

* [AI] Add publishConfig.imports for sync-server to remap aliases to build directory

Co-authored-by: Matiss Janis Aboltins <MatissJanis@users.noreply.github.com>

---------

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-authored-by: Cursor Agent <cursoragent@cursor.com>
Co-authored-by: Matiss Janis Aboltins <MatissJanis@users.noreply.github.com>
2026-04-11 08:56:49 +00:00
20ba076a51 Add rate limiting to authentication endpoints (#7432)
* [AI] Add rate limiting to authentication endpoints

Add strict rate limiting (5 attempts per 15 minutes) to /account/login,
/account/bootstrap, and /account/change-password endpoints to prevent
brute-force password attacks. Uses express-rate-limit as route-level
middleware on auth-sensitive routes only.

https://claude.ai/code/session_017SHnNCn93RzxpvEEPJAZUZ

* [AI] Add release notes and remove rate limit from /change-password

Add upcoming release notes file for the auth rate limiting feature.
Remove rate limiting from /change-password since it already requires
a valid admin session token.

https://claude.ai/code/session_017SHnNCn93RzxpvEEPJAZUZ

---------

Co-authored-by: Claude <noreply@anthropic.com>
2026-04-08 22:21:04 +00:00
Matt FiddamanandGitHub 8511687da4 replace nordigen-node with our own GoCardless implementation (#7352)
* implement our own GoCardless api class

* switch the service to use the new api

* drop deps

* note

* guard against request forgery

* strip empty params from the request body, add error logging

* coderabbit suggestions

* fix test, make institution nullable
2026-04-07 10:33:04 +00:00
Kennedy242GitHubautofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
477fed1607 Add documentation for self-signed cert healthchecks (#7397)
* Add documentation for self-signed cert healthchecks

Adds instruction to set NODE_EXTRA_CA_CERTS in docker-compose healthcheck commands so Node.js can trust the certificate.

* [autofix.ci] apply automated fixes

* fixup! Add documentation for self-signed cert healthchecks

* [autofix.ci] apply automated fixes

* Update Docker health checks with self-signed certs

If using self signed certs, comment the first test line and uncomment
the second test line.

* fixup! Update Docker health checks with self-signed certs

* fixup! Add documentation for self-signed cert healthchecks

* fixup! Update Docker health checks with self-signed certs

* [autofix.ci] apply automated fixes

* fixup! Add documentation for self-signed cert healthchecks

* fixup! Update Docker health checks with self-signed certs

---------

Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
2026-04-07 00:09:35 +00:00
Matt Fiddamanandgithub-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> a12b971670 🔖 (26.4.0) (#7389)
* bump versions

* Remove used release notes

* add docs pages

* Update check-spelling metadata

* bump cli

* change release date

---------

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2026-04-05 18:12:51 +01:00
Matiss Janis AboltinsGitHubClaude Opus 4.6github-actions[bot] <github-actions[bot]@users.noreply.github.com>
c0c2d1630e [AI] Fix password login broken when OIDC is enabled (#7334)
* [AI] Fix password login broken when OIDC is enabled (#7331)

The security fix in PR #7155 added an `active = 1` check to
`getLoginMethod()`, which prevented password login when OIDC was the
active auth method. This caused the server to silently reroute password
login requests to the OpenID flow, which fails.

Remove the `active` requirement when the client explicitly requests a
login method — only require the method to exist in the auth table. The
`active` flag still governs the default method via `getActiveLoginMethod()`.

The `/change-password` endpoint security protections (admin role +
password auth_method checks) remain intact.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* Add release notes for PR #7334

* Update getLoginMethod to validate client-requested login methods against the auth database

Modified the getLoginMethod function to check if the requested login method exists in the auth table before returning it. Updated the corresponding test to reflect that a client-requested method not found in the database will be ignored, ensuring proper handling of login methods.

---------

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2026-04-02 18:34:36 +00:00
dependabot[bot]GitHubdependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>Matt Fiddaman
24382e0e14 Bump convict from 6.2.4 to 6.2.5 (#7293)
* Bump convict from 6.2.4 to 6.2.5

Bumps [convict](https://github.com/mozilla/node-convict) from 6.2.4 to 6.2.5.
- [Changelog](https://github.com/mozilla/node-convict/blob/master/CHANGELOG.md)
- [Commits](https://github.com/mozilla/node-convict/commits)

---
updated-dependencies:
- dependency-name: convict
  dependency-version: 6.2.5
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>

* note

---------

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Matt Fiddaman <github@m.fiddaman.uk>
2026-03-27 19:55:04 +00:00
b6fbc7dd1e [AI] Custom Themes: custom font family (#7239)
* [AI] Add secure custom font support for custom themes

Implement safe font-family references in custom themes via CSS variables
(--font-body, --font-mono, --font-heading, etc.) validated against a
curated allowlist of system-installed and web-safe fonts.

Security approach: Only fonts already present on the user's OS or bundled
with the app are allowed. No @font-face, no url(), no external font
loading — this prevents third-party tracking via font requests while
still enabling meaningful font customization in themes.

Key changes:
- Add SAFE_FONT_FAMILIES allowlist (~80 fonts: generic families, bundled
  fonts, and common system fonts across platforms)
- Add validateFontFamilyValue() for comma-separated font stack validation
- Route --font-{body,mono,heading,family,ui,display,code} properties
  through the font validator instead of the color validator
- Update index.html to use var(--font-body, ...) with current Inter
  Variable stack as fallback
- Add comprehensive tests for valid/invalid font values and security
  edge cases (url injection, javascript:, expression(), etc.)

https://claude.ai/code/session_01D4ASLpcBCvWF1nzPLz9Tw5

* [AI] Add @font-face support with data: URI embedding for custom themes

Enable truly custom fonts in themes while maintaining zero runtime network
requests. Theme authors can include font files in their GitHub repos, and
fonts are automatically downloaded and embedded as data: URIs at install
time — the same approach used for theme CSS itself.

Security model:
- @font-face blocks only allow data: URIs (no http/https/relative URLs)
- Font MIME types are validated (font/woff2, font/ttf, etc.)
- Individual font files capped at 2MB, total at 10MB
- @font-face properties are allowlisted (font-family, src, font-weight,
  font-style, font-display, font-stretch, unicode-range only)
- Font-family names from @font-face are available in --font-* variables
- No runtime network requests — all fonts stored locally after install

Key additions:
- extractFontFaceBlocks(): parse @font-face from theme CSS
- validateFontFaceBlock(): validate properties and data: URIs
- splitDeclarations(): semicolon-aware parser that respects data: URIs
- embedThemeFonts(): fetch font files from GitHub, convert to data: URIs
- ThemeInstaller calls embedThemeFonts() during catalog theme installation
- 30+ new test cases for @font-face validation and security edge cases

Example theme CSS with custom fonts:
  @font-face {
    font-family: 'My Font';
    src: url('./MyFont.woff2') format('woff2');
  }
  :root { --font-body: 'My Font', sans-serif; }

https://claude.ai/code/session_01D4ASLpcBCvWF1nzPLz9Tw5

* [AI] Rename --font-body CSS variable to --font-family

https://claude.ai/code/session_01D4ASLpcBCvWF1nzPLz9Tw5

* [AI] Remove font-family allowlist and broaden --font-* regex

- Remove SAFE_FONT_FAMILIES allowlist and SAFE_FONT_FAMILIES_LOWER lookup.
  Any font name is now valid in --font-* properties. Referencing a font
  that isn't installed simply triggers the browser's normal fallback — no
  network requests, no security risk. Function calls (url(), expression(),
  etc.) are still blocked.

- Change the --font-* property regex from a specific list
  (family|mono|heading|...) to match all --font-* variables, so theme
  authors can use any --font-prefixed custom property.

https://claude.ai/code/session_01D4ASLpcBCvWF1nzPLz9Tw5

* [AI] Simplify and improve custom font validation code

Code quality improvements from review:

- Remove dead `declaredFonts` Set (was populated but never read after
  allowlist removal)
- Extract `stripQuotes()` helper to deduplicate quote-stripping logic
  between `validateFontFamilyValue` and `validateFontFaceBlock`
- Replace confusing `const searchFrom = 0` loop with `for (;;)` idiom
  in `extractFontFaceBlocks`
- Use index tracking (`content.substring(start, i)`) instead of
  character-by-character string concatenation in `splitDeclarations`
- Use `splitDeclarations` in `validateRootContent` instead of naive
  `split(';')` for consistency and correctness
- Parallelize font fetches in `embedThemeFonts` with `Promise.all`
  instead of sequential awaits
- Replace byte-by-byte base64 conversion with chunked
  `arrayBufferToBase64()` helper (8KB chunks)
- Reuse indexOf-based @font-face parsing in `embedThemeFonts` instead
  of fragile `[^}]*` regex that can't handle large data URIs

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* Enhance font validation in customThemes.ts

* Add custom release notes for upcoming feature: support for custom fonts in themes

* [AI] Simplify @font-face validation to only block external URLs

Remove ~210 lines of overly thorough font validation (MIME type allowlists,
base64 encoding checks, format hint validation, @font-face property allowlists,
font-family name regex) and replace with a single function that enforces the
actual security goal: rejecting non-data: URIs to prevent external resource
loading. Size limits for DoS prevention are preserved.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* Update Content Security Policy to include font-src directive

Enhance the Content Security Policy in both the desktop client and sync server to allow font loading from data URIs. This change ensures that custom fonts can be embedded securely while maintaining the existing security measures for other resources.

* Enhance font-family validation to disallow empty values

Update the `validateFontFamilyValue` function to throw an error for empty font-family values, improving security and validation accuracy. Adjust tests to reflect this change, ensuring that empty values are properly handled as invalid.

* Enhance validation for CSS custom properties in customThemes.ts

Add comprehensive checks in the `validateRootContent` function to ensure CSS custom properties start with '--', contain valid characters, and do not end with a dash. This improves error handling for invalid property names, ensuring better compliance with CSS standards.

* [AI] Fix path traversal, spaces in font URLs, and add embedThemeFonts tests

Reject path-traversal (../) and root-anchored (/) font paths in
embedThemeFonts to prevent URL manipulation. Fix URL regex to handle
quoted filenames with spaces (e.g. "Inter Variable.woff2"). Add unit
tests covering both security validations and normal embedding flow.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* Implement font size budget enforcement in embedThemeFonts function

* Add global unstubbing in afterEach for embedThemeFonts tests

---------

Co-authored-by: Claude <noreply@anthropic.com>
2026-03-22 07:58:17 +00:00
Matt FiddamanandGitHub beee16bc8c ⬆️ march dependency updates (#7222)
* @types/node (^22.19.10 → ^22.19.15)

* baseline-browser-mapping (^2.9.19 → ^2.10.0)

* eslint (^9.39.2 → ^9.39.3)

* lage (^2.14.17 → ^2.14.19)

* lint-staged (^16.2.7 → ^16.3.2)

* minimatch (^10.1.2 → ^10.2.4)

* oxlint (^1.47.0 → ^1.51.0)

* rollup-plugin-visualizer (^6.0.5 → ^6.0.11)

* @chromatic-com/storybook (^5.0.0 → ^5.0.1)

* @storybook/addon-a11y (^10.2.7 → ^10.2.16)

* @storybook/addon-docs (^10.2.7 → ^10.2.16)

* @storybook/react-vite (^10.2.7 → ^10.2.16)

* eslint-plugin-storybook (^10.2.7 → ^10.2.16)

* storybook (^10.2.7 → ^10.2.16)

* @codemirror/autocomplete (^6.20.0 → ^6.20.1)

* @codemirror/lang-javascript (^6.2.4 → ^6.2.5)

* @codemirror/language (^6.12.1 → ^6.12.2)

* @rolldown/plugin-babel (~0.1.7 → ~0.1.8)

* @swc/core (^1.15.11 → ^1.15.18)

* @swc/helpers (^0.5.18 → ^0.5.19)

* @tanstack/react-query (^5.90.20 → ^5.90.21)

* @uiw/react-codemirror (^4.25.4 → ^4.25.7)

* hyperformula (^3.1.1 → ^3.2.0)

* i18next (^25.8.4 → ^25.8.14)

* i18next-parser (^9.3.0 → ^9.4.0)

* react-i18next (^16.5.4 → ^16.5.6)

* react-virtualized-auto-sizer (^2.0.2 → ^2.0.3)

* fs-extra (^11.3.3 → ^11.3.4)

* @r74tech/docusaurus-plugin-panzoom (^2.4.0 → ^2.4.2)

* lru-cache (^11.2.5 → ^11.2.6)

* nodemon (^3.1.11 → ^3.1.14)

* eslint-plugin-perfectionist (^4.15.1 → ^5.6.0)

* downshift (9.0.10 → 9.3.2)

* react-router (7.13.0 → 7.13.1)

* @easyops-cn/docusaurus-search-local (^0.52.3 → ^0.55.1)

* peggy (5.0.6 → 5.1.0)

* @types/supertest (^6.0.3 → ^7.2.0)

* note
2026-03-18 08:37:04 +00:00
Matiss Janis AboltinsGitHubClaudegithub-actions[bot] <github-actions[bot]@users.noreply.github.com>
53cdc6fa48 [AI] Further hardening of "/change-password" endpoint (#7207)
* [AI] Fix OIDC privilege escalation in /change-password endpoint

Add admin role check and password auth_method session check to prevent
non-admin or OIDC-authenticated users from changing the server password.
Previously, any authenticated user could overwrite the password hash and
then login via password method to obtain an ADMIN session.

https://claude.ai/code/session_01Wne9FY2QnKp6JF7g61B1Sn

* Add release notes for PR #7207

---------

Co-authored-by: Claude <noreply@anthropic.com>
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2026-03-17 08:16:46 +00:00
Julian Dominguez-SchatzGitHubautofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
a4eb17eff2 Upgrade to Vite 8 (#7184)
* Upgrade to Vite 8

* Add release notes

* PR feedback

* [autofix.ci] apply automated fixes

* PR feedback

* fix: inject process.env

* Restore deleted release note

* Clean up and typecheck

* Fix dev server

* Fix type error

* Fix tests

* PR feedback

---------

Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
2026-03-15 23:16:39 +00:00
Matiss Janis AboltinsGitHubautofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>Cursor AgentMatiss Janis Aboltins
9c61cfc145 [AI] Switch typecheck from tsc to tsgo and fix Menu type narrowing (#7183)
* [AI] Switch typecheck from tsc to tsgo and fix Menu type narrowing

* [autofix.ci] apply automated fixes

* Add .gitignore for dist directory, update typecheck script in package.json to use -b flag, and remove noEmit option from tsconfig.json files in ci-actions and desktop-electron packages. Introduce typesVersions in loot-core package.json for improved type handling.

* Refactor SelectedTransactionsButton to improve type safety and readability. Updated items prop to use spread operator for conditional rendering of menu items, ensuring proper type annotations with MenuItem. This change enhances the clarity of the component's structure and maintains TypeScript compliance.

* Update tsconfig.json in desktop-electron package to maintain consistent formatting for plugins section. No functional changes made.

* [autofix.ci] apply automated fixes

* Update package.json and yarn.lock to add TypeScript 5.8.0 dependency. Adjust typesVersions in loot-core package.json for improved type handling. Enhance tsconfig.json in sync-server package to enable strictFunctionTypes for better type safety.

* Enhance tsconfig.json in ci-actions package by adding composite option for improved project references and build performance.

* [AI] Revert typescript to 5.9.3 for ts-node compatibility

Co-authored-by: Matiss Janis Aboltins <MatissJanis@users.noreply.github.com>

* [AI] Update yarn.lock after TypeScript version change

Co-authored-by: Matiss Janis Aboltins <MatissJanis@users.noreply.github.com>

* Refactor Menu component for improved type safety and readability. Updated type assertions for Menu.line and Menu.label, simplified type checks in filtering and selection logic, and enhanced conditional rendering of menu items. This change ensures better TypeScript compliance and maintains clarity in the component's structure.

* Refactor Select and OpenIdForm components to improve type safety and simplify logic. Updated item mapping to handle Menu.line more effectively, enhancing clarity in selection processes. Adjusted SelectedTransactionsButton to streamline item creation and improve readability.

---------

Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
Co-authored-by: Cursor Agent <cursoragent@cursor.com>
Co-authored-by: Matiss Janis Aboltins <MatissJanis@users.noreply.github.com>
2026-03-14 21:03:10 +00:00
Matiss Janis AboltinsGitHubClaudegithub-actions[bot] <github-actions[bot]@users.noreply.github.com>
541df52441 Enable restrict-template-expressions linting rule (#7181)
* [AI] Promote typescript/restrict-template-expressions to error and fix violations

Convert the oxlint rule from "warn" to "error" and fix all 42 violations
by wrapping non-string template expressions with String(). This ensures
type safety in template literals across the codebase.

https://claude.ai/code/session_01Uk8SwFbD6HuUuo3SSMwU9z

* Add release notes for PR #7181

---------

Co-authored-by: Claude <noreply@anthropic.com>
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2026-03-13 18:36:58 +00:00
Matiss Janis AboltinsGitHubClaudegithub-actions[bot] <github-actions[bot]@users.noreply.github.com>
e968213977 Use TypeScript project references for incremental builds (#7180)
* [AI] Fix duplicate typechecking by consolidating into lage

Previously `yarn typecheck` ran:
1. `tsc -b` (type-checks all packages via project references)
2. `tsc -p tsconfig.root.json --noEmit` (checks root bin/*.ts)
3. `lage typecheck` (runs `tsc --noEmit` per package - duplicate!)

Now it runs:
1. `tsc -p tsconfig.root.json --noEmit` (checks root bin/*.ts)
2. `lage typecheck` (handles everything via dependency ordering)

Changes:
- Remove `tsc -b` from root typecheck script
- Add `dependsOn: ["^typecheck"]` to lage config for correct ordering
- Change per-package typecheck from `tsc --noEmit` to `tsc -b` so
  declarations are emitted for dependent packages

https://claude.ai/code/session_01P7mtAHphD6f1FsnQRwWBaW

* Add release notes for PR #7180

---------

Co-authored-by: Claude <noreply@anthropic.com>
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2026-03-12 21:54:29 +00:00
282a99db2f lint: promote no-floating-promises and require-array-sort-compare to error and fix violations (#7168)
* lint: promote no-floating-promises and require-array-sort-compare to error and fix violations

- Set typescript/no-floating-promises and typescript/require-array-sort-compare to error in .oxlintrc.json
- Add explicit compare functions to all .sort() calls: migrations (localeCompare), crdt/merkle (localeCompare), FiltersMenu (tuple key), useScheduleEdit (two-arg comparator), exec.test (localeCompare), goal-template and category-template-context (numeric), main.test and transactions.test (localeCompare / amount+id)
- Fix invalid single-arg sort in useScheduleEdit to proper two-arg comparator

Made-with: Cursor

* refactor: update sorting functions to use two-argument comparator

* Update index.ts

---------

Co-authored-by: Cursor Agent <cursoragent@cursor.com>
Co-authored-by: Matiss Janis Aboltins <MatissJanis@users.noreply.github.com>
2026-03-12 17:50:37 +00:00
Matiss Janis AboltinsandGitHub bf1d220ced [AI] Lint: fix typescript/unbound-method problems (#7163)
* [AI] Refactor modal components and server modules

Made-with: Cursor

* Release notes
2026-03-10 18:06:50 +00:00
Matiss Janis AboltinsGitHubcoderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
85e08b2e9e [AI] Fix privilege escalation in sync-server /change-password and getLoginMethod (#7155)
* [AI] Fix privilege escalation in sync-server /change-password and getLoginMethod

Made-with: Cursor

* Update upcoming-release-notes/7155.md

Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>

* Fix privilege escalation issue in change-password endpoint

---------

Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
2026-03-09 20:33:20 +00:00
dependabot[bot]GitHubdependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>Cursor AgentMatiss Janis Aboltinsgithub-actions[bot] <github-actions[bot]@users.noreply.github.com>
235d94478f Bump express-rate-limit from 8.2.1 to 8.2.2 (#7140)
* Bump express-rate-limit from 8.2.1 to 8.2.2

Bumps [express-rate-limit](https://github.com/express-rate-limit/express-rate-limit) from 8.2.1 to 8.2.2.
- [Release notes](https://github.com/express-rate-limit/express-rate-limit/releases)
- [Commits](https://github.com/express-rate-limit/express-rate-limit/compare/v8.2.1...v8.2.2)

---
updated-dependencies:
- dependency-name: express-rate-limit
  dependency-version: 8.2.2
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>

* [AI] Update express-rate-limit to 8.3.0 to fix GHSA-46wh-pxpv-q5gq vulnerability

Co-authored-by: Matiss Janis Aboltins <MatissJanis@users.noreply.github.com>

* Add release notes for PR #7140

* [AI] Update release notes to reflect version 8.3.0

Co-authored-by: Matiss Janis Aboltins <MatissJanis@users.noreply.github.com>

---------

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Cursor Agent <cursoragent@cursor.com>
Co-authored-by: Matiss Janis Aboltins <MatissJanis@users.noreply.github.com>
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2026-03-07 19:48:56 +00:00
Michael ClarkandGitHub b727124603 Fix docker images (#7146)
* fix docker images

* release notes
2026-03-06 22:55:21 +00:00
387c8fce16 [AI] Enable TypeScript composite project references across monorepo (#7062)
* [AI] Enable TypeScript composite project references across monorepo

- Add composite and declaration emit to all package tsconfigs
- Wire root and per-package project references in dependency order
- Replace cross-package include-based typing with referenced outputs
- Fix api TS5055 by emitting declarations to decl-output
- Add desktop-client alias for tests; fix oxlint import order in vite.config
- Add UsersState.data null type and openDatabase return type for strict emit

Co-authored-by: Cursor <cursoragent@cursor.com>

* Remove obsolete TypeScript configuration for API and update build script to emit declarations directly to the output directory. This streamlines the build process and ensures compatibility with the new project structure.

* Refactor TypeScript configuration in API package to remove obsolete decl-output directory and update build scripts. The changes streamline the build process by directing declaration outputs to the @types directory, ensuring better organization and compatibility with the new project structure.

* Add TypeScript declaration emission for loot-core in desktop-electron build process

* Refactor TypeScript configuration in API package to utilize composite references and streamline build scripts. Update include and exclude patterns for improved file management, ensuring better organization of declaration outputs and migration SQL files.

* Refactor TypeScript configuration in loot-core and desktop-client packages to streamline path management and remove obsolete dependencies. Update paths in tsconfig.json files for better organization and compatibility, and adjust yarn.lock to reflect changes in workspace dependencies.

* Update desktop-electron package to utilize loot-core as a workspace dependency. Adjust TypeScript import paths and tsconfig references for improved organization and compatibility across packages.

* Enhance Vite configuration for desktop-client to support Electron-specific conditions and update loot-core package.json to include Electron as a platform for client connection. This improves compatibility for Electron builds.

* Refactor TypeScript configuration across multiple packages to streamline path management. Update tsconfig.json files in root, api, and loot-core packages to improve import paths and maintain compatibility with internal typings.

* Update package dependencies and Vite configuration across component-library and desktop-client. Add vite-tsconfig-paths to component-library and remove it from desktop-client. Refactor Storybook preview file to include a TODO for future refactoring.

* Remove Node-specific path from loot-core package.json for client connection, streamlining platform configuration for Electron.

* Remove loot-core as a workspace dependency from desktop-electron package.json

* Update tsconfig.json to remove reference to desktop-client

---------

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-03-04 20:57:06 +00:00
Julian Dominguez-SchatzandGitHub cb8ff337dc Migrate sync server general utils to typescript (#7074)
* Migrate sync server general utils to typescript

* Add release notes

* Rabbit

* Fix
2026-03-04 16:40:24 +00:00