mirror of
https://github.com/actualbudget/actual.git
synced 2026-07-15 14:43:36 -05:00
api-browser-custom-data-dir
447 Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
5fc6f7638c |
Check in mobile app scaffolding generated by Capacitor (#8387)
* Check in app scaffolding generated by Capacitor All files generated by `npx cap init` and `npx cap sync`. * Add release notes * Add package.json file * Update capacitor * Prune deps * CodeRabbit feedback |
||
|
|
e8c7f8040e |
bcrypt -> argon2id (#7829)
* bcrypt -> argon2id * coderabbit feedback * copilot review * switch hashing settings * [AI] Add unit tests for sync-server password hashing Cover password.js, focused on the bcrypt -> argon2id migration: - loginWithPassword upgrades a legacy bcrypt hash to argon2id on a successful login, leaves it untouched on a failed login, and does not needlessly rehash an existing argon2id hash - hashPassword/verifyPassword round-trip, bcrypt backward-compat, and graceful handling of non-string/malformed hashes - bootstrapPassword/changePassword/checkPassword behaviour Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * dedupe minimatch --------- Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com> |
||
|
|
cbc056536b |
Bump js-yaml in the npm_and_yarn group across 1 directory (#8379)
Bumps the npm_and_yarn group with 1 update in the / directory: [js-yaml](https://github.com/nodeca/js-yaml). Updates `js-yaml` from 3.14.2 to 3.15.0 - [Changelog](https://github.com/nodeca/js-yaml/blob/master/CHANGELOG.md) - [Commits](https://github.com/nodeca/js-yaml/compare/3.14.2...3.15.0) --- updated-dependencies: - dependency-name: js-yaml dependency-version: 3.15.0 dependency-type: indirect dependency-group: npm_and_yarn ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> |
||
|
|
8ad218b7d9 |
[AI] api: make the browser build work in consumer production bundles (#8289)
* api: make the browser build work in consumer production bundles
The browser build shipped `new Worker(new URL("./worker.js", import.meta.url))`
in dist/browser.js. A consumer bundler (Vite/Rollup) recognizes that as a worker
entry and re-bundles the already-prebuilt worker.js from scratch, which desyncs
the absurd-sql/connection RPC so `init` throws a structured-clone error. It only
worked in dev and in the package's own e2e because both serve dist verbatim.
Make the browser build fully self-contained instead:
- Inline the worker into browser.js and spawn it from a Blob URL, so consumer
bundlers never see a worker entry to re-bundle. The worker is built as an IIFE
(classic worker), mirroring the web app's kcab.worker.
- Embed the sql.js wasm and the default filesystem data (migrations + default
DB) into the worker so it performs no PUBLIC_URL asset fetches:
- loot-core sqlite gains an opt-in `setWasmBinary` (dormant for web/node);
- the worker installs a scoped fetch shim serving the embedded data/* files
from a sentinel base URL.
- Share the asset-collection logic between the Node disk copy and the embedded
build via scripts/embedded-assets.mjs so the two never drift.
Result: `import '@actual-app/api'` + `init()` works in any bundler with zero
config; only COOP/COEP headers remain required (SharedArrayBuffer).
Adds an e2e (e2e/consumer + e2e/global-setup.mjs) that builds a real consumer
app for production and boots it under COOP/COEP — coverage the verbatim-dist
harness can't provide. Docs note the build is self-contained and that
cross-origin isolation is still required.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
* [AI] api: address review feedback (guard DOM lookup, revoke blob URL on worker failure)
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
* [AI] api: address review nitpicks (drop BodyInit cast, reword release note)
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
* [AI] api: build the browser worker via Vite ?worker&inline
Replace the hand-rolled worker inlining (a custom Vite plugin that read the
prebuilt worker.js off disk and inlined it as a string, plus a second build
config and a build-ordering dependency) with Vite's native `?worker&inline`
import. This collapses the two browser build configs into one, removes the
`virtual:actual-worker-code` module and the manual Blob URL spawn, and drops
the worker-before-facade build step.
Vite's `?worker&inline` sub-build doesn't receive vite-plugin-node-polyfills'
global-shim injection (the plugin writes it to `build.rollupOptions`, but the
worker sub-build reads `worker.rollupOptions`), so the worker crashed on
`process is not defined`. Patch the plugin to also emit the injection on
`worker.rollupOptions` — additive and backwards compatible (the web app build,
including loot-core's nodePolyfills worker, is unaffected).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
* [AI] api: embed browser assets via Vite, drop the embedded-assets script
Replace scripts/embedded-assets.mjs with Vite-native asset imports in the
worker entry: `?inline` for the sql.js wasm and default DB, `import.meta.glob`
(`?raw`) for the migrations. The worker builds the default-filesystem wire
format from those at module load, so the embedded set comes straight from
loot-core and can't drift.
The Node build only needs migrations + the default DB on disk (it reads them at
runtime); the old script also wrote sql-wasm.wasm and the data/ fetch tree,
which are dead now that the browser worker is self-contained. Replace
writeEmbeddedAssetsToDist with a small closeBundle copy of just those two.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
* [AI] api: simplify embedded data map; drop loot-core comment churn
Merge the worker's binData/textData into a single dataFiles map (Response
accepts both bytes and strings), collapsing the fetch shim's two lookups into
one. Revert the unrelated comment edits to loot-core's backend-worker.ts and
fs/index.ts.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
* [AI] api: rename e2e consumer-dist to consumer/dist; drop a prose comment
Use the standard `dist` directory name for the consumer fixture's build output
(now e2e/consumer/dist), and remove the verbose comment from index.browser.ts.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
* [AI] loot-core: own the default-filesystem assets; consumers stop reaching in
Add packages/loot-core/default-filesystem.mjs as the single source of truth for
loot-core's runtime assets (sql.js wasm, default DB, migrations) and the
data-file-index wire format, exported as @actual-app/core/default-filesystem.
- @actual-app/api: the browser worker embeds them via the actual-embedded-assets
Vite plugin (which calls collectEmbeddedAssets), replacing the relative
?inline/?raw/import.meta.glob reaches into ../loot-core; the Node build copies
migrations + default DB using the helper's paths. Drops the direct
@jlongster/sql.js devDependency (loot-core resolves the wasm).
- @actual-app/web: stagePublicData copies from the helper's paths instead of
hardcoding loot-core's tree and the sql.js wasm location.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
* [AI] loot-core: scan migrations once when collecting embedded assets
collectEmbeddedAssets() read the migrations directory twice — once in its
own loop and once via buildDataFileIndex(). List the names once and pass
them through, keeping the index wire-format defined in a single place.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
|
||
|
|
c4acaa2951 |
[AI] Add knip to detect unused files, dependencies and exports (#8309)
Adds the knip tool with a monorepo-tuned config (knip.json) and a CI gate in check.yml, plus the dead-code and dependency cleanup it surfaced. The unused-export/type/duplicate rules are disabled so exporting an unused symbol is allowed. Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com> |
||
|
|
60c5d9b993 |
[AI] DX: replace ts-node with Node native TypeScript execution (#8304)
* [AI] Replace ts-node with Node native TypeScript execution Node 22.18+ runs TypeScript files directly via type stripping, so the ts-node dependency is no longer needed for the repo's helper scripts. - Run bin/ and loot-core pack-hook scripts with `node` instead of `ts-node` - Rename bin/*.ts scripts to .mts (unambiguous ESM, runs warning-free) - ESM-ify validate-publish-imports: __dirname / require.main via import.meta - Drop ts-node devDependency and the tsconfig ts-node override block - Bump engines.node to >=22.18.0 (first release with stable type stripping) Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019d6S7BWQdmtAcYg89WuAVd * [AI] Use .mts import specifier and simplify release note Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019d6S7BWQdmtAcYg89WuAVd * [AI] Bump .nvmrc to v22.18.0 to match engines floor Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019d6S7BWQdmtAcYg89WuAVd --------- Co-authored-by: Claude <noreply@anthropic.com> |
||
|
|
3a894b1bf6 |
[AI] Reduce dependencies (lodash, ua-parser-js, memoize-one, promise-retry, resize-observer polyfill) (#8278)
* [AI] Reduce dependencies (lodash, ua-parser-js, memoize-one, promise-retry, resize-observer polyfill) Remove or replace several low-usage / native-coverable dependencies to shrink the dependency surface and transitive deps: - lodash -> es-toolkit (es-toolkit/compat) for the 5 functions in use (debounce, keyBy, isMatch, isEqual, uniqueId) - ua-parser-js -> inline UA regex checks in loot-core shared/platform - memoize-one -> small local memoizeOne helper in loot-core shared - promise-retry -> small local retry helper (loot-core shared + a local copy in desktop-electron, which loads compiled JS at runtime) - @juggle/resize-observer polyfill removed; native ResizeObserver is supported by all current targets uuid was intentionally left untouched: crypto.randomUUID is only available in secure contexts, which would break self-hosted instances served over plain HTTP (including loot-core code running in the browser web worker). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01JdZrw7VVwyF6VJgb34U9Qo * [AI] Use es-toolkit main entry for keyBy in report spreadsheets The two report spreadsheet files only used keyBy from es-toolkit/compat. Switch them to the lighter main es-toolkit entry (which takes a key function instead of a string), so these chunks no longer pull in the compat layer. Runtime behavior is identical. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01JdZrw7VVwyF6VJgb34U9Qo * [AI] Rename release note to slug and reword for readability Rename the dependency-reduction release note from the guessed PR number to a descriptive slug, and reword the body to read clearly as changelog content. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01JdZrw7VVwyF6VJgb34U9Qo * [AI] Shorten release note wording Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01JdZrw7VVwyF6VJgb34U9Qo * [AI] Harden retry helper against sync throws; simplify memoizeOne typing - retry: run fn inside a promise chain so synchronous throws (and synchronous retry() calls) are routed through the rejection handler instead of escaping uncaught. Applied to both loot-core and desktop-electron copies. - memoizeOne: use separate Args/Result generics and drop the `as T` cast. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01JdZrw7VVwyF6VJgb34U9Qo * [AI] Update yarn.lock after merge and install Co-authored-by: Matiss Janis Aboltins <MatissJanis@users.noreply.github.com> --------- Co-authored-by: Claude <noreply@anthropic.com> Co-authored-by: Cursor Agent <cursoragent@cursor.com> Co-authored-by: Matiss Janis Aboltins <MatissJanis@users.noreply.github.com> |
||
|
|
c1c4856aa7 |
Bump dompurify in the npm_and_yarn group across 1 directory (#8286)
Bumps the npm_and_yarn group with 1 update in the / directory: [dompurify](https://github.com/cure53/DOMPurify). Updates `dompurify` from 3.4.10 to 3.4.11 - [Release notes](https://github.com/cure53/DOMPurify/releases) - [Commits](https://github.com/cure53/DOMPurify/compare/3.4.10...3.4.11) --- updated-dependencies: - dependency-name: dompurify dependency-version: 3.4.11 dependency-type: indirect dependency-group: npm_and_yarn ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> |
||
|
|
c74923eb30 |
[AI] Replace vite-plugin-peggy-loader with an in-repo Vite plugin (#8285)
* [AI] Replace vite-plugin-peggy-loader with in-repo Peggy plugin Drop the third-party vite-plugin-peggy-loader dependency in favor of a small in-repo Vite plugin (packages/loot-core/scripts/peggy.mts) that compiles .pegjs grammars using the existing peggy dependency. Wire it into the loot-core and api vite/vitest configs, and remove the now-dead loader from the component-library config (it imports no grammars). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Up3H4YR7L8Qb4UKxbasyMp * [AI] Host the Peggy Vite plugin in a workspace package Move the in-repo Peggy loader out of packages/loot-core/scripts and into a dedicated private workspace package, @actual-app/vite-plugin-peggy, so the loot-core and api configs reference it as a normal workspace dependency instead of reaching across packages with ../loot-core relative imports. The peggy dependency now lives with the plugin that uses it. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Up3H4YR7L8Qb4UKxbasyMp * [AI] Rename release note to match PR number Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Up3H4YR7L8Qb4UKxbasyMp --------- Co-authored-by: Claude <noreply@anthropic.com> |
||
|
|
8f27e177dc |
[AI] api: add browser build (#8166)
* [AI] api: add browser build
Continuation of #7545 (and #8143, which moved the browser Web Worker
bootstrap into loot-core). This adds the browser-compatible build of
@actual-app/api: the full loot-core stack runs inside a Web Worker and a
thin main-thread facade exposes the same public surface as the Node entry.
loot-core:
- Add platform/client/backend-worker.ts: createBackendWorker(worker)
centralizes absurd-sql's main-thread initBackend + __absurd:* message
filtering, and is exported for the api to reuse.
- Refactor browser-preload's start.ts and worker-bridge.ts to route through
it (drops the duplicated __absurd:* filtering; terminate() now also clears
listeners). Behavior is preserved.
api:
- browser-worker.ts: Web Worker entry owning real loot-core, speaking
loot-core's {id,name,args} backend protocol; wraps fetch to map the
.js -> .js.data migration names.
- index.browser.ts: main-thread facade that spawns the worker.
- browser/rpc.ts: main-thread <-> worker RPC bridge (uses createBackendWorker).
- browser/lib-stub.ts: stubs lib.send so methods.ts routes over postMessage.
- vite.browser.config.mts / vite.browser-worker.config.mts and asset bundling
in vite.config.mts (sql-wasm.wasm + data/ + data-file-index.txt); package.json
build chain, browser export, and absurd-sql/npm-run-all/vite-plugin-node-polyfills deps.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* [AI] Rename release note to match PR number 8166
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* [AI] api: move browser worker plumbing into loot-core
Address review feedback: the browser worker logic shouldn't live in the api
package since it's generic "loot-core as a browser npm package" plumbing, not
api-specific. Resolve it via loot-core's existing conditional-export system
instead of a vite alias.
- loot-core: add server/main.api-browser.ts (worker-routing `lib` that
delegates to the existing platform/client/connection), selected via a new
`api-browser` export condition on "./server/main". Move the worker entry to
server/api-browser-worker.ts.
- api: the facade (index.browser.ts) now reuses loot-core's client connection
via a minimal global.Actual.getServerSocket shim and spawns the worker built
from loot-core's entry. Deletes browser-worker.ts, browser/rpc.ts and
browser/lib-stub.ts (~270 lines) in favor of the shared loot-core code.
- The facade build selects the impl with resolve.conditions: ['api-browser']
instead of resolve.alias, removing the enforce-boundaries lint exception.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* [AI] api: simplify browser build cleanups
Post-review cleanups (no behavior change):
- backend-worker.ts: fix stale doc comment referencing the removed
packages/api/browser/rpc.ts (the consumer is now index.browser.ts).
- api-browser-worker.ts: drop the redundant `endsWith('/data-file-index.txt')`
disjunct (subsumed by `endsWith('data-file-index.txt')`) and the no-op
`input as RequestInfo | URL` re-casts on the fetch pass-throughs.
- index.browser.ts: replace the single-field `state` holder with a plain
module-level `let backend`.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* [AI] api: drop the createBackendWorker wrapper, revert browser-preload churn
Now that the facade rides on loot-core's platform/client/connection (which
already ignores absurd-sql's `__`-prefixed internal messages), the only thing
the main thread still needs is absurd's one-line initBackend. So:
- Replace the 60-line createBackendWorker wrapper (onMessage/postMessage/
terminate/listener filtering) with a tiny initBrowserBackend(worker) helper.
- Revert browser-preload/start.ts and worker-bridge.ts to their merged state —
they keep importing absurd's initBackend directly, so this PR no longer
refactors just-merged files and the loot-core change is purely additive.
- Facade holds a plain Worker handle and calls worker.terminate() on shutdown.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* [AI] api: trim verbose comments in the browser build
Keep only the load-bearing "why" notes (the absurd-sql init, the fetch/.js.data
workaround, the global.Actual shim, the api-browser condition); drop protocol
diagrams, usage examples, and restated context. No code/behavior change.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* [AI] api: drop redundant absurd-sql dependency
No api source imports absurd-sql; it's reached only through @actual-app/core
(the facade's initBrowserBackend and the bundled worker), which declares it.
It's bundled into the build output, so it isn't a runtime dependency of the
published package either. Bundles are byte-for-byte unchanged.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* [AI] api: drop the api-browser condition, inject the worker into the connection
Review feedback: the api-browser export condition fought loot-core's idiom
(browser IS the default platform; node/"api" is the override) and hid a bug —
the condition-swapped lib only had `send`, so api.utils.amountToInteger was
silently undefined in the browser build.
Replace the condition with a plain transport seam:
- methods.ts no longer imports server/main; it sends through api/send.ts,
which the Node entry wires to in-process lib.send and the browser entry
wires to loot-core's client connection. utils.ts re-exports
amountToInteger/integerToAmount from shared/util directly (fixes the bug).
- loot-core's client connection init() now accepts an optional injected
socket; connectBackendWorker(worker) installs absurd-sql's bridge and
connects in one call. This removes the forged global.Actual shim and the
facade's `define: { global: 'globalThis' }` workaround. Desktop's argless
init() path is unchanged.
- Delete main.api-browser.ts, the "./server/main" conditional export, and
the facade's resolve.conditions.
The 4 loot-core snapshot failures (main.test.ts / transfer.test.ts) are
pre-existing on the branch without these changes.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* [AI] api: route methods through the client connection, slim the facade
Review feedback: get rid of the _setSend seam and move the worker init logic
into loot-core.
- methods.ts now imports `send` from loot-core's client connection. The node
build resolves it via the existing `api` condition to a new in-process
implementation (platform/client/connection/index.api.ts — previously a dead
re-export of the electron client), matching the platform idiom: browser is
the default, node/"api" overrides. api/send.ts is deleted and the node
entry (index.ts) reverts to master byte-for-byte.
- loot-core's startBackendWorker(worker, config, assetsBaseUrl) now owns the
whole worker boot (absurd-sql bridge + connection.init + server init RPC),
so the browser entry just spawns the worker and calls it.
- Trims: single chained build script (drops the npm-run-all dep), copyFileSync
instead of the linkOrCopy helper, drop the worker entry's error listeners
(browsers already log worker uncaughts to DevTools).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* [AI] api: trim prose comments to the essential ones
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* [AI] fix client connection stalling when no sends are queued at connect
Found while smoke-testing the browser api build in a real consumer app: the
client connection only nulled messageQueue (switching from queueing to direct
postMessage) when the queue was non-empty at 'connect'. The desktop app always
has queued sends by then, so it never hits this; the api facade connects
before sending anything, so every later send queued forever and init() hung.
Drop the queue on connect unconditionally.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* [AI] fix client connection dropping api/* error replies
Found via the browser smoke test: opening an e2e-encrypted budget without the
key surfaced as "undefined is not an object" instead of an error. The server
connection forwards api/* handler failures as {type:'reply', id, error}, but
the web client connection only read `result`, silently resolving undefined for
every failed api/* call. Reject when the reply carries an error, matching the
server's envelope (and the old api rpc behavior). The electron client has the
same latent gap; left untouched here.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* [AI] api: move the worker entry back into the api package
Review feedback: browser-worker.ts is the api package's build entry, not
generic loot-core code — move it back (it now imports loot-core through the
public @actual-app/core exports instead of #-subpaths).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* [AI] api: drop the manifest rewrite, align shutdown, trim comments
The data-file-index.txt manifest now lists migrations under their real .js
names (the worker's fetch shim already redirects those to the .js.data files
on disk), so the manifest-rewriting half of the shim is gone. The worker init
payload carries config and assetsBaseUrl as separate fields instead of
smuggling a private key into the config object, browser shutdown() mirrors
the node facade, and the client connection's queue flush drops a redundant
branch.
* [AI] fix rejected handler promises poisoning close-budget
runHandler only removed a method's promise from runningMethods when it
fulfilled, so any handler rejection left a stale promise in the set. The next
close-budget then failed: flushRunningMethods' Promise.all rejected with that
old, unrelated error before closeBudget even ran. Remove settled promises on
rejection too, and flush with Promise.allSettled since rejected methods
already reported their error to their caller.
* [AI] api: add a browser e2e test
A Playwright test loads the built browser bundle in chromium from a static
COOP/COEP server and exercises the full stack: worker boot, the rejected-error
contract, budget import, transaction read-back, and IndexedDB persistence
across a page reload. A dedicated workflow runs it in CI on api/loot-core
changes.
* [AI] api: drop the worker fetch shim; strip .data names in loot-core fs
The .js.data scheme was spread across three coordinated pieces: the build
renamed migrations on disk, the manifest listed names that didn't exist, and
a global fetch monkey-patch in the worker un-lied at runtime. Now the
manifest lists the true on-disk names and populateDefaultFilesystem (the only
fetcher of these files) strips the .data suffix when naming the virtual file
— the fetch patch is gone and the suffix becomes a small documented fs
convention. Also: e2e static server uses a single stat and drops a dead MIME
entry.
* [AI] fix electron client connection dropping api/* error replies
Both server connection variants post api/* handler failures as
{type: 'reply', id, error}, but only the web client rejected on it
(
|
||
|
|
e0880f3901 |
Bump the npm_and_yarn group across 1 directory with 2 updates (#8272)
Bumps the npm_and_yarn group with 2 updates in the / directory: [http-proxy-middleware](https://github.com/chimurai/http-proxy-middleware) and [undici](https://github.com/nodejs/undici). Updates `http-proxy-middleware` from 3.0.6 to 3.0.7 - [Release notes](https://github.com/chimurai/http-proxy-middleware/releases) - [Changelog](https://github.com/chimurai/http-proxy-middleware/blob/v3.0.7/CHANGELOG.md) - [Commits](https://github.com/chimurai/http-proxy-middleware/compare/v3.0.6...v3.0.7) Updates `undici` from 7.27.2 to 7.28.0 - [Release notes](https://github.com/nodejs/undici/releases) - [Commits](https://github.com/nodejs/undici/compare/v7.27.2...v7.28.0) --- updated-dependencies: - dependency-name: http-proxy-middleware dependency-version: 3.0.7 dependency-type: direct:development dependency-group: npm_and_yarn - dependency-name: undici dependency-version: 7.28.0 dependency-type: indirect dependency-group: npm_and_yarn ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> |
||
|
|
1ad52d7128 |
Bump the npm_and_yarn group across 1 directory with 6 updates (#8253)
Bumps the npm_and_yarn group with 6 updates in the / directory: | Package | From | To | | --- | --- | --- | | [dompurify](https://github.com/cure53/DOMPurify) | `3.4.2` | `3.4.10` | | [form-data](https://github.com/form-data/form-data) | `4.0.5` | `4.0.6` | | [launch-editor](https://github.com/vitejs/launch-editor) | `2.12.0` | `2.14.1` | | [tar](https://github.com/isaacs/node-tar) | `7.5.13` | `7.5.16` | | [webpack-dev-server](https://github.com/webpack/webpack-dev-server) | `5.2.4` | `5.2.5` | | [ws](https://github.com/websockets/ws) | `7.5.10` | `7.5.11` | Updates `dompurify` from 3.4.2 to 3.4.10 - [Release notes](https://github.com/cure53/DOMPurify/releases) - [Commits](https://github.com/cure53/DOMPurify/compare/3.4.2...3.4.10) Updates `form-data` from 4.0.5 to 4.0.6 - [Release notes](https://github.com/form-data/form-data/releases) - [Changelog](https://github.com/form-data/form-data/blob/master/CHANGELOG.md) - [Commits](https://github.com/form-data/form-data/compare/v4.0.5...v4.0.6) Updates `launch-editor` from 2.12.0 to 2.14.1 - [Commits](https://github.com/vitejs/launch-editor/compare/v2.12.0...v2.14.1) Updates `tar` from 7.5.13 to 7.5.16 - [Release notes](https://github.com/isaacs/node-tar/releases) - [Changelog](https://github.com/isaacs/node-tar/blob/main/CHANGELOG.md) - [Commits](https://github.com/isaacs/node-tar/compare/v7.5.13...v7.5.16) Updates `webpack-dev-server` from 5.2.4 to 5.2.5 - [Release notes](https://github.com/webpack/webpack-dev-server/releases) - [Changelog](https://github.com/webpack/webpack-dev-server/blob/main/CHANGELOG.md) - [Commits](https://github.com/webpack/webpack-dev-server/compare/v5.2.4...v5.2.5) Updates `ws` from 7.5.10 to 7.5.11 - [Release notes](https://github.com/websockets/ws/releases) - [Commits](https://github.com/websockets/ws/compare/7.5.10...7.5.11) --- updated-dependencies: - dependency-name: dompurify dependency-version: 3.4.10 dependency-type: indirect dependency-group: npm_and_yarn - dependency-name: form-data dependency-version: 4.0.6 dependency-type: indirect dependency-group: npm_and_yarn - dependency-name: launch-editor dependency-version: 2.14.1 dependency-type: indirect dependency-group: npm_and_yarn - dependency-name: tar dependency-version: 7.5.16 dependency-type: indirect dependency-group: npm_and_yarn - dependency-name: webpack-dev-server dependency-version: 5.2.5 dependency-type: indirect dependency-group: npm_and_yarn - dependency-name: ws dependency-version: 7.5.11 dependency-type: indirect dependency-group: npm_and_yarn ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> |
||
|
|
df00ff2028 |
Bump joi in the npm_and_yarn group across 1 directory (#8239)
Bumps the npm_and_yarn group with 1 update in the / directory: [joi](https://github.com/hapijs/joi). Updates `joi` from 17.13.3 to 17.13.4 - [Commits](https://github.com/hapijs/joi/compare/v17.13.3...v17.13.4) --- updated-dependencies: - dependency-name: joi dependency-version: 17.13.4 dependency-type: indirect dependency-group: npm_and_yarn ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> |
||
|
|
de245df61f |
Upgrade pluggy-sdk and migrate away from deprecated page-size transactions to cursor-based transactions (#8103)
* Bump pluggy-sdk to include new fetchTransactionsCursor GET /v2/transactions * Use fetchAllTransactions, which uses cursor-based /v2/transactions * Remove weak helper function * Add release note * Fix unused result mapping * Add lelemm's changes Co-authored by: lelemm * Fix lint * Add lelemm as co-author on release note * Update message * Fix comma typo * Update yarn.lock --------- Co-authored-by: Matt Fiddaman <github@m.fiddaman.uk> |
||
|
|
fbdad57ff0 |
⬆️ mid month dependency updates (#8235)
* @monorepo-utils/workspaces-to-typescript-project-references (^2.10.3 → ^2.11.0) * @types/node (^22.19.17 → ^22.19.21) * eslint (^10.2.0 → ^10.5.0) * eslint-plugin-perfectionist (^5.8.0 → ^5.9.0) * lage (^2.15.5 → ^2.15.13) * typescript (^6.0.2 → ^6.0.3) * vitest (^4.1.2 → ^4.1.8) * better-sqlite3 (^12.8.0 → ^12.10.0) * vite (^8.0.5 → ^8.0.16) * cosmiconfig (^9.0.1 → ^9.0.2) * react-aria-components (^1.16.0 → ^1.18.0) * @chromatic-com/storybook (^5.1.1 → ^5.2.1) * @storybook/addon-a11y (^10.3.4 → ^10.4.4) * @storybook/addon-docs (^10.3.4 → ^10.4.4) * @storybook/react-vite (^10.3.4 → ^10.4.4) * @types/react (^19.2.14 → ^19.2.17) * @vitejs/plugin-react (^6.0.1 → ^6.0.2) * eslint-plugin-storybook (^10.3.4 → ^10.4.4) * storybook (^10.3.4 → ^10.4.4) * @bufbuild/protobuf (^2.11.0 → ^2.12.0) * @bufbuild/protoc-gen-es (^2.11.0 → ^2.12.0) * @babel/core (^7.29.0 → ^7.29.7) * @codemirror/autocomplete (^6.20.1 → ^6.20.3) * @react-aria/interactions (^3.27.1 → ^3.28.1) * @reduxjs/toolkit (^2.11.2 → ^2.12.0) * @tanstack/react-query (^5.96.2 → ^5.101.0) * @uiw/react-codemirror (^4.25.9 → ^4.25.10) * date-fns (^4.1.0 → ^4.4.0) * hyperformula (^3.2.0 → ^3.3.0) * lru-cache (^11.2.7 → ^11.5.1) * react-aria (^3.47.0 → ^3.49.0) * react-error-boundary (^6.1.1 → ^6.1.2) * react-hotkeys-hook (^5.2.4 → ^5.3.2) * react-redux (^9.2.0 → ^9.3.0) * react-spring (^10.0.3 → ^10.0.4) * rolldown (^1.0.0-rc.13 → ^1.1.1) * sass (^1.99.0 → ^1.101.0) * vite-plugin-pwa (^1.2.0 → ^1.3.0) * @docusaurus/core (^3.10.0 → ^3.10.1) * @docusaurus/plugin-content-docs (^3.10.0 → ^3.10.1) * @docusaurus/plugin-ideal-image (^3.10.0 → ^3.10.1) * @docusaurus/preset-classic (^3.10.0 → ^3.10.1) * @docusaurus/theme-common (^3.10.0 → ^3.10.1) * @docusaurus/theme-mermaid (^3.10.0 → ^3.10.1) * @easyops-cn/docusaurus-search-local (^0.55.1 → ^0.55.2) * @docusaurus/module-type-aliases (^3.10.0 → ^3.10.1) * @oxlint/plugins (^1.60.0 → ^1.69.0) * ua-parser-js (^2.0.9 → ^2.0.10) * fast-check (^4.6.0 → ^4.8.0) * jest-diff (^30.3.0 → ^30.4.1) * workbox-precaching (^7.4.0 → ^7.4.1) * ipaddr.js (^2.3.0 → ^2.4.0) * jws (^3.2.2 → ^3.2.3) * http-proxy-middleware (^3.0.5 → ^3.0.6) * oxlint (^1.59.0 → ^1.69.0) * @codemirror/view (^6.41.0 → ^6.43.1) * yarn dedupe * nano-staged (^0.8.0 → ^1.0.2) * commander (^14.0.3 → ^15.0.0) * react (>=19.2 → 19.2.7) * react-dom (>=19.2 → 19.2.7) * @rolldown/plugin-babel (~0.1.8 → ~0.2.3) * downshift (9.3.2 → 9.3.6) * i18next (^25.10.10 → ^26.3.1) * react-i18next (^16.6.6 → ^17.0.8) * react-router (7.15.0 → 7.17.0) * vite-plugin-node-polyfills (^0.27.0 → ^0.28.0) * jws (^3.2.3 → ^4.0.1) * oxlint-tsgolint (^0.20.0 → ^0.23.0) * jsdom (^27.4.0 → ^29.1.1) * note * [autofix.ci] apply automated fixes * [autofix.ci] apply automated fixes (attempt 2/3) * crdt regenerate and version bump * fix test * yarn dedupe --------- Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com> |
||
|
|
c31219291c |
Bump esbuild in the npm_and_yarn group across 1 directory (#8213)
Bumps the npm_and_yarn group with 1 update in the / directory: [esbuild](https://github.com/evanw/esbuild). Updates `esbuild` from 0.25.10 to 0.25.12 - [Release notes](https://github.com/evanw/esbuild/releases) - [Changelog](https://github.com/evanw/esbuild/blob/main/CHANGELOG-2025.md) - [Commits](https://github.com/evanw/esbuild/compare/v0.25.10...v0.25.12) --- updated-dependencies: - dependency-name: esbuild dependency-version: 0.25.12 dependency-type: indirect dependency-group: npm_and_yarn ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> |
||
|
|
351f544498 |
Bump shell-quote in the npm_and_yarn group across 1 directory (#8182)
Bumps the npm_and_yarn group with 1 update in the / directory: [shell-quote](https://github.com/ljharb/shell-quote). Updates `shell-quote` from 1.8.3 to 1.8.4 - [Changelog](https://github.com/ljharb/shell-quote/blob/main/CHANGELOG.md) - [Commits](https://github.com/ljharb/shell-quote/compare/v1.8.3...v1.8.4) --- updated-dependencies: - dependency-name: shell-quote dependency-version: 1.8.4 dependency-type: indirect dependency-group: npm_and_yarn ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> |
||
|
|
328417f8de |
[AI] Consolidate agent tooling and simplify developer guidance (#8089)
* [AI] Replace mechanical agent rules with shared agent hooks + nano-staged Move the mechanical "remember to run X" rules out of AGENTS.md and the agent guidance docs into deterministic, cross-agent hooks, and migrate the pre-commit runner from lint-staged to nano-staged. - Add shared hook scripts in scripts/agent-hooks/ (git-guard, format-edited-file, no-strict-ignore-new-file, prefer-one-component, check-on-stop, common helpers) wired for Claude (.claude/settings.json), Codex (.codex/config.toml), and Cursor (.cursor/hooks.json + adapters). - Enforce "avoid enum" via a new actual/no-enum lint rule, grandfathering the two existing declarations in .oxlintrc.json overrides. - Migrate lint-staged -> nano-staged (.nano-staged.json, .husky/pre-commit, package.json). - Trim AGENTS.md, .github/agents/pr-and-commit-rules.md, the Cursor rule, and the committing skill down to the rules that aren't auto-enforced. - Add release note 8089.md. * [AI] Align PR-title wording in AGENTS.md with canonical rules * [AI] Fix check-on-stop hook on bash 3.2 and TSV column collapse The Stop hook silently no-op'd in two ways: - `declare -A` isn't supported on stock macOS bash 3.2, and the slash/hyphen path subscript aborted under `set -u`. Dedupe via a space-padded string match instead. - jq emitted an empty middle TSV field for a package with test but no typecheck; tab is IFS-whitespace so `read` collapsed it and shifted the columns (eslint-plugin-actual then ran neither). Emit non-empty sentinels (-, yes/no) so no field can collapse. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> --------- Co-authored-by: Claude <noreply@anthropic.com> |
||
|
|
ebcb86ab7d |
[AI] Move browser web-worker logic into loot-core (#8143)
* [AI] Move browser web-worker logic into loot-core Relocate the browser Web Worker bootstrap (WorkerBridge + startBrowserBackend) and the multi-tab SharedWorker coordinator from desktop-client into loot-core so they can be reused (e.g. by the api package in a browser). Behavior is preserved as faithfully as possible. The two Vite worker entry targets stay in desktop-client (the browser-server.js classic worker and the ?sharedworker entry); the ?sharedworker entry now imports the coordinator from loot-core. console.* calls in the moved code route through loot-core's logger, except the SharedWorker console-forwarding mechanism, which must keep the real console. absurd-sql's initBackend is imported directly (loot-core already depends on absurd-sql); the desktop-client dependency was dropped. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * [AI] Rename release note to match PR number 8143 * Update release notes for Web Worker migration Removed mention of reuse by the API package in the release notes. * [AI] Drop move-related header comments per review Remove the "moved from desktop-client" header comments that only made sense in the context of this PR. worker-bridge.ts and start.ts had no header comment in the original source, so they're removed entirely; coordinator.ts's header is restored to its original wording. --------- Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com> |
||
|
|
f1c0960fee |
Feature: Add Akahu New Zealand bank sync (#6041)
* add akahu integration for nz banks * akahu fix bank name being set to account name * rename apiToken and fix reset pointing to the wrong function * fix apitoken wording in akahu init modal * add upcoming-release-notes * fix lint issues * fix lint issues * add loan account type to starting balance inversion * fix initial sync balance * initially select 365 days of transactions on first sync for akahu sync * add SyncServerAkahuAccount to onSetLinkedAccount * set transaction currency to account currency * remove unnecessary code * handle TFR TO/FROM payees and account for loan account type in transactions * [autofix.ci] apply automated fixes * rename Error to ErrorAlert and fix intial sync start date * extract note from description for TFR TO/FROM transactions * fix normalizeNotes not referencing the transaction * refactor app-akahu code * [autofix.ci] apply automated fixes * Add Akahu to ExternalAccount type * Update yarn.lock * update yarn.lock * Remove unused error var in catch block * [autofix.ci] apply automated fixes * require authentication for akahu endpoint * fix lint issue in mutations.ts * fix up import paths * fix lint issues * reorder form fields * remove unnecessary handling for debt accounts * lint fixes * Put Akahu bank sync under feature flag * remove incorrect feedback link * [autofix.ci] apply automated fixes * Add feedback link for feature toggle * use uuidv4 * prevent fetch if feature not enabled * change app-akahu to ts and tidy up * fix typecheck errors * [autofix.ci] apply automated fixes * fix browser client build issues * [autofix.ci] apply automated fixes * update akahu npm package to latest version * use amountToInteger for balance reducer * add additional details to transactions * change initial sync start date logic * add akahu fields to mappable fields in desktop-client * [autofix.ci] apply automated fixes * getDate use formatISO to get the timezone adjusted date * remove duplicate payeeName --------- Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com> |
||
|
|
e934258dc8 |
Bump react-router in the npm_and_yarn group across 1 directory (#8072)
Bumps the npm_and_yarn group with 1 update in the / directory: [react-router](https://github.com/remix-run/react-router/tree/HEAD/packages/react-router). Updates `react-router` from 7.14.2 to 7.15.0 - [Release notes](https://github.com/remix-run/react-router/releases) - [Changelog](https://github.com/remix-run/react-router/blob/main/packages/react-router/CHANGELOG.md) - [Commits](https://github.com/remix-run/react-router/commits/react-router@7.15.0/packages/react-router) --- updated-dependencies: - dependency-name: react-router dependency-version: 7.15.0 dependency-type: direct:development dependency-group: npm_and_yarn ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> |
||
|
|
e9f7e3672b |
Bump the npm_and_yarn group across 2 directories with 1 update (#8071)
Bumps the npm_and_yarn group with 1 update in the / directory: [react-router](https://github.com/remix-run/react-router/tree/HEAD/packages/react-router). Bumps the npm_and_yarn group with 1 update in the /packages/desktop-client directory: [react-router](https://github.com/remix-run/react-router/tree/HEAD/packages/react-router). Updates `react-router` from 7.13.1 to 7.14.2 - [Release notes](https://github.com/remix-run/react-router/releases) - [Changelog](https://github.com/remix-run/react-router/blob/main/packages/react-router/CHANGELOG.md) - [Commits](https://github.com/remix-run/react-router/commits/react-router@7.14.2/packages/react-router) Updates `react-router` from 7.13.1 to 7.14.2 - [Release notes](https://github.com/remix-run/react-router/releases) - [Changelog](https://github.com/remix-run/react-router/blob/main/packages/react-router/CHANGELOG.md) - [Commits](https://github.com/remix-run/react-router/commits/react-router@7.14.2/packages/react-router) --- updated-dependencies: - dependency-name: react-router dependency-version: 7.14.2 dependency-type: direct:development dependency-group: npm_and_yarn - dependency-name: react-router dependency-version: 7.14.2 dependency-type: direct:development dependency-group: npm_and_yarn ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> |
||
|
|
75dd9f674a |
[AI] Add auto-generated Upcoming Release docs page (#8065)
* [AI] Add auto-generated Upcoming Release docs page Adds a docs page that always reflects the current contents of the repo-root upcoming-release-notes/ directory — the changes that have been merged but not yet published in a stable release (i.e. what ships in the nightly/edge builds). - Extract parseReleaseNotes/formatNotes from the release-notes generator into the shared ci-actions util so both the release generator and the docs build reuse the same formatting. - Add a docs build script that regenerates docs/upcoming-release-notes.md on every start/build, with an intro explaining the notes are unreleased and how to try them, plus the categorized notes list. - Wire the generator into the docs start/build scripts, add a sidebar entry next to Release Notes, and gitignore the generated page. https://claude.ai/code/session_01MuY9Phome8uJKH51HbrsQw * [AI] Simplify upcoming-release-notes generator - Declare @actual-app/ci-actions as a workspace dependency and import the shared util by package name instead of a relative cross-package path, so the dependency is registered in the workspace graph. - Resolve the repo root once via new URL() and drop the dirname import. - Use a ternary for the page body instead of let + if/else. https://claude.ai/code/session_01MuY9Phome8uJKH51HbrsQw * Add release notes for PR #8065 * [AI] Remove edge references, keep only nightly in docs Co-authored-by: Matiss Janis Aboltins <MatissJanis@users.noreply.github.com> * Update packages/docs/scripts/generate-upcoming-release-notes.mjs Co-authored-by: Matt Fiddaman <github@m.fiddaman.uk> --------- Co-authored-by: Claude <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> Co-authored-by: Matt Fiddaman <github@m.fiddaman.uk> |
||
|
|
3f7439f180 |
[AI] Scope Electron update to v41 (#8044)
* Initial plan * Bump desktop Electron runtime to v42.3.0 * Add release notes entry for PR #8044 * Change author from Copilot to MikesGlitch Updated author information in release notes. * Update node-abi mappings to support Electron 42 ABI detection * Address validation feedback for Electron update PR * Add better-sqlite3 Electron 42 patch * Update lockfile for better-sqlite3 patch * Remove better-sqlite patch protocol and target Electron 41 * Align release note with Electron 41.7.1 change * Update better-sqlite3 ranges to ^12.8.0 --------- Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: Michael Clark <5285928+MikesGlitch@users.noreply.github.com> Co-authored-by: Matt Fiddaman <github@m.fiddaman.uk> |
||
|
|
7f4a0e7d6b |
[AI] Move i18n usage outside of loot-core (#8027)
* [AI] Move i18n usage outside of loot-core
loot-core should be platform-agnostic and free of i18n concerns. This
moves all user-facing translated string helpers (rule/schedule labels,
error formatters) into desktop-client's #util/{rule,schedule,error}
modules, while keeping the underlying logic in loot-core.
- Headless @actual-app/api error formatters in loot-core now return
plain English strings (the API has no i18n runtime).
- The persisted "Unknown" institution name and the platform storage
alert use plain strings.
- Removed the unused i18next dependency from loot-core.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* [AI] Address review feedback on i18n-out-of-loot-core PR
- Wrap switch default arms in blocks to satisfy noSwitchDeclarations
(desktop-client and loot-core getDownloadError)
- getSecretsError: return a localized generic message instead of leaking
the raw backend error token
- getRecurringDescription: always separate the weekend annotation so it no
longer renders as "Monday(after weekend)"; add test coverage
- IndexedDB quota error: surface a typed 'indexeddb-quota-error' event from
loot-core and present the localized alert in desktop-client instead of a
hard-coded English string
- Persist a null bank name (instead of English "Unknown") when the provider
reports no institution, and render a localized fallback in the bank sync UI
---------
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
|
||
|
|
c02dfc0d29 |
[AI] Fix docusaurus docs build (#8018)
* [AI] Fix docs build by pinning webpackbar to v7 webpack 5.106+ removed deprecated ProgressPlugin options, which breaks the older webpackbar 6.0.1 that Docusaurus 3.10.0 depends on. The build fails with "Progress Plugin has been initialized using an options object that does not match the API schema" (unknown properties name/color/ reporters/reporter). Add a webpackbar ^7.0.0 resolution, matching the upstream fix in Docusaurus 3.10.1 (facebook/docusaurus#11981). * Add release notes for PR #8018 --------- Co-authored-by: Claude <noreply@anthropic.com> Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com> |
||
|
|
ff70d2d5f8 |
[AI] Upgrade dependencies to resolve security advisories (#7982)
* [AI] Upgrade dependencies to resolve security advisories Resolve 9 Dependabot security alerts via version upgrades: - rollup: remove the resolutions pin that forced workbox-build's rollup ^2.79.2 up to vulnerable 4.40.1; it now resolves to the patched 2.80.0 (vite 8 uses rolldown, so no rollup 4.x is needed) (CVE-2026-27606) - serialize-javascript: add resolution ^7.0.5 (build-time only; consumers are deep-transitive webpack/terser plugins pinned to ^6) (GHSA-5c6j-r48x-rmvq, CVE-2026-34043) - express-rate-limit ^8.3.2 -> ^8.5.2, pulling ip-address 10.2.0 (CVE-2026-42338) - refresh in-range transitives: bn.js 5.2.3, ajv 8.20.0, glob 10.5.0, path-to-regexp 8.4.2 (CVE-2026-2739, CVE-2025-69873, CVE-2025-64756, CVE-2026-4926, CVE-2026-4923) Not addressed: elliptic (CVE-2025-14505) has no patched release; uuid 8.3.2 (dev-only via sockjs, not reachable) left as-is. https://claude.ai/code/session_018obbND7t9dBZvfvUBBJKFz * [AI] Remove redundant minimatch resolution pins Five of the six minimatch resolutions were no-ops: their consumers use caret ranges (^3.x, ^5.x, ^9.x, ^10.x) that already float to versions patched against CVE-2026-26996 (3.1.5, 5.1.9, 9.0.9, 10.2.5). Only serve-handler pins minimatch to exactly 3.1.2 (vulnerable), so the single targeted "minimatch@3.1.2" override is kept. The resolved lockfile is unchanged. https://claude.ai/code/session_018obbND7t9dBZvfvUBBJKFz * Add release notes for PR #7982 --------- Co-authored-by: Claude <noreply@anthropic.com> Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com> |
||
|
|
be5804717a |
Bump the npm_and_yarn group across 1 directory with 3 updates (#7980)
Bumps the npm_and_yarn group with 3 updates in the / directory: [ip-address](https://github.com/beaugunderson/ip-address), [tmp](https://github.com/raszi/node-tmp) and [webpack](https://github.com/webpack/webpack). Updates `ip-address` from 10.0.1 to 10.1.0 - [Commits](https://github.com/beaugunderson/ip-address/compare/v10.0.1...v10.1.0) Updates `tmp` from 0.2.5 to 0.2.7 - [Changelog](https://github.com/raszi/node-tmp/blob/master/CHANGELOG.md) - [Commits](https://github.com/raszi/node-tmp/compare/v0.2.5...v0.2.7) Updates `webpack` from 5.102.1 to 5.107.2 - [Release notes](https://github.com/webpack/webpack/releases) - [Changelog](https://github.com/webpack/webpack/blob/main/CHANGELOG.md) - [Commits](https://github.com/webpack/webpack/compare/v5.102.1...v5.107.2) --- updated-dependencies: - dependency-name: ip-address dependency-version: 10.1.0 dependency-type: indirect dependency-group: npm_and_yarn - dependency-name: tmp dependency-version: 0.2.7 dependency-type: indirect dependency-group: npm_and_yarn - dependency-name: webpack dependency-version: 5.107.2 dependency-type: indirect dependency-group: npm_and_yarn ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> |
||
|
|
8d5f903b54 |
Bump qs from 6.15.1 to 6.15.2 (#7932)
Bumps [qs](https://github.com/ljharb/qs) from 6.15.1 to 6.15.2. - [Changelog](https://github.com/ljharb/qs/blob/main/CHANGELOG.md) - [Commits](https://github.com/ljharb/qs/compare/v6.15.1...v6.15.2) --- updated-dependencies: - dependency-name: qs dependency-version: 6.15.2 dependency-type: indirect ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> |
||
|
|
fb4b0aaba8 |
fix: Add glob-hasher-linux-arm64-gnu as optional dependency to fix yarn typecheck error on ARM64 containers (#7917)
* fix: Add glob-hasher-linux-arm64-gnu as optional dependency for ARM64 containers * docs: Add release notes for PR #7916 * Renamed `upcoming-release-notes/7916.md` → `7917.md` * [autofix.ci] apply automated fixes --------- Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com> |
||
|
|
802fde5dbe |
Bump ws from 7.5.10 to 8.20.1 (#7895)
Bumps [ws](https://github.com/websockets/ws) from 7.5.10 to 8.20.1. - [Release notes](https://github.com/websockets/ws/releases) - [Commits](https://github.com/websockets/ws/compare/7.5.10...8.20.1) --- updated-dependencies: - dependency-name: ws dependency-version: 8.20.1 dependency-type: indirect ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> |
||
|
|
ffb3c1b708 |
Bump webpack-dev-server from 5.2.2 to 5.2.4 (#7896)
Bumps [webpack-dev-server](https://github.com/webpack/webpack-dev-server) from 5.2.2 to 5.2.4. - [Release notes](https://github.com/webpack/webpack-dev-server/releases) - [Changelog](https://github.com/webpack/webpack-dev-server/blob/main/CHANGELOG.md) - [Commits](https://github.com/webpack/webpack-dev-server/compare/v5.2.2...v5.2.4) --- updated-dependencies: - dependency-name: webpack-dev-server dependency-version: 5.2.4 dependency-type: indirect ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> |
||
|
|
46c350613c |
[AI] Upgrade vite-plugin-node-polyfills to 0.27.0 (#7860)
* [AI] Upgrade vite-plugin-node-polyfills to 0.27.0 Bumps `vite-plugin-node-polyfills` from `^0.26.0` to `^0.27.0` in `packages/loot-core`. Changelog: https://github.com/davidmyersdev/vite-plugin-node-polyfills/releases/tag/v0.27.0 Related upstream issue (already referenced from `vite.config.mts`): https://github.com/davidmyersdev/vite-plugin-node-polyfills/issues/142 * [AI] Add release note for vite-plugin-node-polyfills upgrade * [AI] Remove stale upstream issue reference from vite config The link pointed at davidmyersdev/vite-plugin-node-polyfills#142, which no longer needs a workaround note alongside the `nodePolyfills` call. --------- Co-authored-by: Claude <noreply@anthropic.com> |
||
|
|
740392941d |
Bump qs from 6.13.0 to 6.15.1 (#7857)
Bumps [qs](https://github.com/ljharb/qs) from 6.13.0 to 6.15.1. - [Changelog](https://github.com/ljharb/qs/blob/main/CHANGELOG.md) - [Commits](https://github.com/ljharb/qs/compare/v6.13.0...v6.15.1) --- updated-dependencies: - dependency-name: qs dependency-version: 6.15.1 dependency-type: indirect ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> |
||
|
|
d4528e18ea |
Bump lodash-es from 4.17.21 to 4.18.1 (#7854)
Bumps [lodash-es](https://github.com/lodash/lodash) from 4.17.21 to 4.18.1. - [Release notes](https://github.com/lodash/lodash/releases) - [Commits](https://github.com/lodash/lodash/compare/4.17.21...4.18.1) --- updated-dependencies: - dependency-name: lodash-es dependency-version: 4.18.1 dependency-type: indirect ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> |
||
|
|
a7e22b023c |
Disable postinstall scripts except for an allowlist (#7825)
* Disable postinstall scripts except for an allowlist
* Add release notes
* Temp: trigger docs CI
* Revert "Temp: trigger docs CI"
This reverts commit
|
||
|
|
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> |
||
|
|
8263e58eb2 |
[AI] Replace payee and category autocomplete filter/sort with fzf fuzy search (#7261)
* [AI] feat(web): replace custom autocomplete ranking with fzf Replace substring-based filter/sort in PayeeAutocomplete and CategoryAutocomplete with fzf fuzzy search. Remove deprecated autocompleteRanking utility. Closes #7261 * Update #7261 release notes Co-authored-by: Matt Fiddaman <github@m.fiddaman.uk> * Update VRT screenshots Auto-generated by VRT workflow PR: #7261 * Regenerate yarn.lock file * Update VRT screenshots Auto-generated by VRT workflow PR: #7261 * Restore e2e snapshots * Update VRT screenshots Auto-generated by VRT workflow PR: #7261 --------- Co-authored-by: Nadir Miralimov <riid@pm.me> Co-authored-by: Matt Fiddaman <github@m.fiddaman.uk> Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com> |
||
|
|
f3a9c1a02c |
Bump mermaid from 11.12.1 to 11.15.0 (#7801)
Bumps [mermaid](https://github.com/mermaid-js/mermaid) from 11.12.1 to 11.15.0. - [Release notes](https://github.com/mermaid-js/mermaid/releases) - [Commits](https://github.com/mermaid-js/mermaid/compare/mermaid@11.12.1...mermaid@11.15.0) --- updated-dependencies: - dependency-name: mermaid dependency-version: 11.15.0 dependency-type: indirect ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> |
||
|
|
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 |
||
|
|
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>
|
||
|
|
b63f5dd303 |
Bump fast-uri from 3.1.0 to 3.1.2 (#7762)
Bumps [fast-uri](https://github.com/fastify/fast-uri) from 3.1.0 to 3.1.2. - [Release notes](https://github.com/fastify/fast-uri/releases) - [Commits](https://github.com/fastify/fast-uri/compare/v3.1.0...v3.1.2) --- updated-dependencies: - dependency-name: fast-uri dependency-version: 3.1.2 dependency-type: indirect ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> |
||
|
|
35a01b0fa6 |
Bump @babel/plugin-transform-modules-systemjs from 7.28.5 to 7.29.4 (#7776)
Bumps [@babel/plugin-transform-modules-systemjs](https://github.com/babel/babel/tree/HEAD/packages/babel-plugin-transform-modules-systemjs) from 7.28.5 to 7.29.4. - [Release notes](https://github.com/babel/babel/releases) - [Changelog](https://github.com/babel/babel/blob/main/CHANGELOG.md) - [Commits](https://github.com/babel/babel/commits/v7.29.4/packages/babel-plugin-transform-modules-systemjs) --- updated-dependencies: - dependency-name: "@babel/plugin-transform-modules-systemjs" dependency-version: 7.29.4 dependency-type: indirect ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> |
||
|
|
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> |
||
|
|
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
|
||
|
|
ff0f5bdb35 |
[AI] lage - move browser build to using lage (#7602)
* Simplify desktop client browser build * [AI] Move browser build orchestration into vite config and lage Moves loot-core worker build, public/ staging (migrations, default-db, sql-wasm, data-file-index), and build-stats wiring from the deleted packages/desktop-client/bin/build-browser shell script into a lootCoreBackend vite plugin in packages/desktop-client/vite.config.mts. Adds a build:browser target to lage.config.js so bin/package-browser runs as a single `lage build:browser --to=@actual-app/web` call, with crdt + loot-core built via lage's ^build dependency before the desktop-client build. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * Refactor e2e-test workflow and update desktop-client configurations * [AI] Move plugins-service staging into desktop-client vite config Declares plugins-service as a workspace devDependency of @actual-app/web so lage's ^build edge picks it up automatically in the build:browser pipeline, and moves the cross-package file staging (production copy + dev serving) into vite.config.mts, mirroring the lootCoreBackend pattern. Drops the plugins-service shell wrapper script and simplifies its package.json scripts to invoke vite build directly. Updates root start:browser to run plugins-service watch in parallel with the dev server instead of pre-building once. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * [AI] Sync tsconfig project references for plugins-service edge Follow-up to the plugins-service workspace edge: adds the ../plugins-service project reference in packages/desktop-client/tsconfig.json via yarn sync:tsconfig-references. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * Release notes * [AI] Ignore .venv/ so lage's git hasher skips Electron CI's Python venv Electron CI provisions a Python virtualenv at the repo root for setuptools. With browser builds now routed through lage, lage's git hash-object pass walks untracked-not-ignored files and fails on the venv's broken lib64 symlink ("fatal: Unable to hash .../.venv/lib64"). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * [AI] Bake Weblate translations back into VRT/e2e bundle build-web set download-translations: false and relied on bin/package-browser's ad-hoc git clone + git pull. That path is fragile inside the playwright container, so vite's import.meta.glob('/locale/*.json') frequently produced an empty languages map and the bundle shipped with no en.json. VRTs then rendered source-code English and diffed against snapshots authored from Weblate strings. Route translation provisioning back through actions/checkout (download-translations: true) in build-web and vrt-update-generate, and add --skip-translations to bin/package-browser (mirroring bin/package-electron) so the in-script git pull is bypassed when CI has already staged the locale dir. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * [AI] Skip translation cloning in build-web bundle for VRT determinism bin/package-browser used to unconditionally clone actualbudget/translations before vite ran, baking Weblate en.json into the build artifact. With the e2e-test pipeline now serving that artifact via serve-build.mjs, VRT screenshots ended up rendering Weblate strings — drifting from the snapshots, which were authored against source-code English (master VRTs ran on vite dev without a locale dir). Pass --skip-translations to bin/package-browser from build-web so the bundle ships with no locale chunks. download-translations stays 'false' across the e2e-test and vrt-update-generate workflows, matching the prior behavior. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com> |
||
|
|
9acbd6388b |
[AI] Cache the CLI's local budget between invocations (#7539)
* [AI] Cache the CLI's local budget between invocations
Every `actual <cmd>` call currently delta-syncs the budget with the
sync server via `api.downloadBudget`, which hits the server's
500-req/min rate limit on scripted workflows. Actual is local-first:
once the budget is on disk, most read commands do not need fresh
server data.
Introduce a CLI-only cache layer inside `withConnection` that
decides per invocation whether to skip, sync, or re-download:
- Cache state lives at `{dataDir}/.actual-cli/{syncId}/state.json`,
keyed by `syncId` to avoid the chicken-and-egg of not knowing the
on-disk `budgetId` before the first download. The on-disk id is
resolved via `api.getBudgets()` and persisted after first download.
- Read commands (list, balance, query run, …) skip the `/sync`
call while `now - lastSyncedAt < cacheTtl`. Write commands
(create, update, delete, set-*, etc.) sync before and after the
operation to keep server state consistent.
- Encrypted budgets force a sync per call since `api/load-budget`
does not re-verify the password.
- New `proper-lockfile`-backed shared/exclusive lock serializes
writes while allowing parallel reads. Reader markers live in
`{meta}/readers/`; writers sweep stale markers by PID.
New `actual sync` command with three modes: default (sync now),
`--status` (print cache age, TTL, stale flag), `--clear` (delete
cache, holding the exclusive lock to avoid racing writers).
New config surface, following the existing flag → env → config file
→ default precedence chain:
- `--cache-ttl <s>` / `ACTUAL_CACHE_TTL` / `cacheTtl` (default 60)
- `--refresh` / `--no-cache`
- `--lock-timeout <s>` / `ACTUAL_LOCK_TIMEOUT` / `lockTimeout` (10)
- `--no-lock` / `ACTUAL_NO_LOCK` / `noLock`
Every `withConnection` call site now passes an explicit
`{ mutates: boolean, skipBudget?: boolean }` so read/write intent is
visible at the edge.
The old `budgets sync` subcommand is removed — it silently diverged
from the new top-level `actual sync`.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* [AI] Simplify CLI cache/lock internals
Use a discriminated SyncDecision union so connection.ts no longer needs
non-null assertions on the cached state. Thread the resolved CliConfig
through withConnection's callback to drop duplicate resolveConfig calls
in the sync and budgets commands. Extract an errorCode helper and
replace the existsSync+readdirSync TOCTOU pattern in the reader-wait
polling loop with a single readdir that tolerates ENOENT.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* [AI] Address PR #7539 review comments
- cache.ts: use a unique per-writer tmp filename so concurrent shared-
lock writers (encrypted budgets, --refresh, stale TTL) don't clobber
each other's publish and silently drop state updates.
- index.ts/config.ts: fix --no-cache and --no-lock flags. Commander
stores --no-foo under the positive key (cache/lock) and an explicit
false default makes the flag a no-op; the previous code also read
the wrong keys (noCache/noLock) so the flags had no effect at all.
Derive refresh/noLock from the correct keys.
- budgets.ts: invert encryption password precedence so the subcommand
flag (--encryption-password) wins over env/config-file values.
- sync.ts: report stale=true in --status when lastSyncedAt is in the
future, matching decideSyncAction's clock-skew handling.
- connection.ts: drop unnecessary `as` cast on api.getBudgets() now
that the return type is Promise<APIFileEntity[]>.
- utils.ts: parseBoolEnv throws on unrecognized values instead of
silently returning undefined so typos like ACTUAL_NO_LOCK=yes fail
loudly.
- Shorten 7539 release note to a single user-facing sentence.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
||
|
|
4f1bc3fcdd |
Bump postcss from 8.5.8 to 8.5.10 (#7613)
* Bump postcss from 8.5.8 to 8.5.10 Bumps [postcss](https://github.com/postcss/postcss) from 8.5.8 to 8.5.10. - [Release notes](https://github.com/postcss/postcss/releases) - [Changelog](https://github.com/postcss/postcss/blob/main/CHANGELOG.md) - [Commits](https://github.com/postcss/postcss/compare/8.5.8...8.5.10) --- updated-dependencies: - dependency-name: postcss dependency-version: 8.5.10 dependency-type: indirect ... Signed-off-by: dependabot[bot] <support@github.com> * Add release notes for postcss version bump Updated postcss version for maintenance. --------- Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Julian Dominguez-Schatz <julian.dominguezschatz@gmail.com> |
||
|
|
c8224d24be |
Bump @xmldom/xmldom from 0.8.12 to 0.8.13 (#7596)
Bumps [@xmldom/xmldom](https://github.com/xmldom/xmldom) from 0.8.12 to 0.8.13. - [Release notes](https://github.com/xmldom/xmldom/releases) - [Changelog](https://github.com/xmldom/xmldom/blob/master/CHANGELOG.md) - [Commits](https://github.com/xmldom/xmldom/compare/0.8.12...0.8.13) --- updated-dependencies: - dependency-name: "@xmldom/xmldom" dependency-version: 0.8.13 dependency-type: indirect ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> |
||
|
|
bd1da27404 |
Bump dompurify from 3.3.2 to 3.4.1 (#7591)
Bumps [dompurify](https://github.com/cure53/DOMPurify) from 3.3.2 to 3.4.1. - [Release notes](https://github.com/cure53/DOMPurify/releases) - [Commits](https://github.com/cure53/DOMPurify/compare/3.3.2...3.4.1) --- updated-dependencies: - dependency-name: dompurify dependency-version: 3.4.1 dependency-type: indirect ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Matiss Janis Aboltins <matiss@mja.lv> |