From 78b1fc271359e2e2d549d41d48dcdcbaac375ce3 Mon Sep 17 00:00:00 2001 From: Matiss Janis Aboltins Date: Sun, 12 Apr 2026 17:11:26 +0100 Subject: [PATCH] [AI] Add no-extraneous-dependencies lint rule (#7480) * [AI] Add no-extraneous-dependencies lint rule to prevent transitive dependency usage Closes #7479. Adds a custom ESLint rule that flags imports of packages not explicitly listed in the workspace's dependencies or devDependencies. Also fixes all existing violations by adding missing deps and removes unused deps (@reduxjs/toolkit, @rschedule/json-tools) from loot-core. Co-Authored-By: Claude Opus 4.6 (1M context) * [AI] Fix builtin subpath detection and improve cache in no-extraneous-dependencies Fix false positives for Node.js builtin subpaths (fs/promises, path/posix) by checking the package name portion against builtins. Also cache all visited directories during walk-up, not just the starting directory. Co-Authored-By: Claude Opus 4.6 (1M context) * Release notes --------- Co-authored-by: Claude Opus 4.6 (1M context) --- .oxlintrc.json | 1 + package.json | 3 +- packages/ci-actions/package.json | 1 + packages/desktop-client/package.json | 7 + packages/desktop-electron/package.json | 2 + packages/eslint-plugin-actual/lib/index.js | 1 + .../no-extraneous-dependencies.test.js | 94 +++++++ .../lib/rules/no-extraneous-dependencies.js | 136 ++++++++++ packages/loot-core/package.json | 8 +- upcoming-release-notes/7480.md | 6 + yarn.lock | 247 +++++++++++++++++- 11 files changed, 491 insertions(+), 15 deletions(-) create mode 100644 packages/eslint-plugin-actual/lib/rules/__tests__/no-extraneous-dependencies.test.js create mode 100644 packages/eslint-plugin-actual/lib/rules/no-extraneous-dependencies.js create mode 100644 upcoming-release-notes/7480.md diff --git a/.oxlintrc.json b/.oxlintrc.json index eebfefd6b1..871f5e89f1 100644 --- a/.oxlintrc.json +++ b/.oxlintrc.json @@ -37,6 +37,7 @@ "actual/no-anchor-tag": "error", "actual/no-react-default-import": "error", "actual/prefer-subpath-imports": "error", + "actual/no-extraneous-dependencies": "error", // JSX A11y rules "jsx-a11y/no-autofocus": [ diff --git a/package.json b/package.json index 79b53e911f..27b36a139e 100644 --- a/package.json +++ b/package.json @@ -85,7 +85,8 @@ "p-limit": "^7.3.0", "prompts": "^2.4.2", "ts-node": "^10.9.2", - "typescript": "^5.9.3" + "typescript": "^5.9.3", + "vitest": "^4.1.0" }, "resolutions": { "adm-zip": "patch:adm-zip@npm%3A0.5.16#~/.yarn/patches/adm-zip-npm-0.5.16-4556fea098.patch", diff --git a/packages/ci-actions/package.json b/packages/ci-actions/package.json index 4268e08ad1..99df7445e6 100644 --- a/packages/ci-actions/package.json +++ b/packages/ci-actions/package.json @@ -8,6 +8,7 @@ "typecheck": "tsgo -b" }, "devDependencies": { + "@octokit/rest": "^22.0.1", "@typescript/native-preview": "^7.0.0-dev.20260309.1", "extensionless": "^2.0.6", "gray-matter": "^4.0.3", diff --git a/packages/desktop-client/package.json b/packages/desktop-client/package.json index 58863a93a1..09af710837 100644 --- a/packages/desktop-client/package.json +++ b/packages/desktop-client/package.json @@ -121,6 +121,8 @@ "@juggle/resize-observer": "^3.4.0", "@lezer/highlight": "^1.2.3", "@playwright/test": "1.58.2", + "@react-aria/interactions": "^3.27.0", + "@reduxjs/toolkit": "^2.11.2", "@rolldown/plugin-babel": "~0.1.8", "@rollup/plugin-inject": "^5.0.5", "@swc/core": "^1.15.18", @@ -141,19 +143,23 @@ "@use-gesture/react": "^10.3.1", "@vitejs/plugin-basic-ssl": "^2.2.0", "@vitejs/plugin-react": "^6.0.0", + "absurd-sql": "0.0.54", "auto-text-size": "^0.2.3", "babel-plugin-react-compiler": "^1.0.0", "cmdk": "^1.1.1", "cross-env": "^10.1.0", "date-fns": "^4.1.0", "downshift": "9.3.2", + "html-to-image": "^1.11.13", "hyperformula": "^3.2.0", "i18next": "^25.8.14", "i18next-parser": "^9.4.0", "i18next-resources-to-backend": "^1.2.1", "jsdom": "^27.4.0", "lodash": "^4.18.1", + "lru-cache": "^11.2.6", "mdast-util-newline-to-break": "^2.0.0", + "memoize-one": "^6.0.0", "pikaday": "1.8.2", "promise-retry": "^2.0.1", "re-resizable": "^6.11.2", @@ -178,6 +184,7 @@ "recharts": "^3.7.0", "rehype-external-links": "^3.0.0", "remark-gfm": "^4.0.1", + "rolldown": "^1.0.0-rc.12", "rollup-plugin-visualizer": "^6.0.11", "sass": "^1.97.3", "typescript-strict-plugin": "^2.4.4", diff --git a/packages/desktop-electron/package.json b/packages/desktop-electron/package.json index cea8651405..0a4d6c1933 100644 --- a/packages/desktop-electron/package.json +++ b/packages/desktop-electron/package.json @@ -22,7 +22,9 @@ }, "devDependencies": { "@actual-app/core": "workspace:*", + "@actual-app/web": "workspace:*", "@electron/notarize": "3.1.1", + "@electron/rebuild": "^4.0.3", "@playwright/test": "1.58.2", "@types/copyfiles": "^2", "@types/fs-extra": "^11", diff --git a/packages/eslint-plugin-actual/lib/index.js b/packages/eslint-plugin-actual/lib/index.js index a6a1e95d65..ff29501010 100644 --- a/packages/eslint-plugin-actual/lib/index.js +++ b/packages/eslint-plugin-actual/lib/index.js @@ -13,5 +13,6 @@ module.exports = { 'no-anchor-tag': require('./rules/no-anchor-tag'), 'no-react-default-import': require('./rules/no-react-default-import'), 'prefer-subpath-imports': require('./rules/prefer-subpath-imports'), + 'no-extraneous-dependencies': require('./rules/no-extraneous-dependencies'), }, }; diff --git a/packages/eslint-plugin-actual/lib/rules/__tests__/no-extraneous-dependencies.test.js b/packages/eslint-plugin-actual/lib/rules/__tests__/no-extraneous-dependencies.test.js new file mode 100644 index 0000000000..fcc5fb8375 --- /dev/null +++ b/packages/eslint-plugin-actual/lib/rules/__tests__/no-extraneous-dependencies.test.js @@ -0,0 +1,94 @@ +import { runClassic } from 'eslint-vitest-rule-tester'; + +import * as rule from '../no-extraneous-dependencies'; + +void runClassic( + 'no-extraneous-dependencies', + rule, + { + valid: [ + // Relative imports are always allowed + `import foo from './foo'`, + `import foo from '../foo'`, + + // Subpath imports are always allowed + `import foo from '#utils/foo'`, + + // Node.js built-ins are allowed (including subpaths) + `import fs from 'fs'`, + `import path from 'path'`, + `import crypto from 'node:crypto'`, + `import { readFile } from 'fs/promises'`, + `import posix from 'path/posix'`, + + // Virtual modules are allowed + `import { registerSW } from 'virtual:pwa-register'`, + + // require() with relative path + `const foo = require('./foo')`, + ], + + invalid: [ + { + code: `import foo from 'not-a-real-package'`, + errors: [ + { + messageId: 'extraneous', + data: { packageName: 'not-a-real-package' }, + }, + ], + }, + { + code: `import foo from '@not-real/package'`, + errors: [ + { + messageId: 'extraneous', + data: { packageName: '@not-real/package' }, + }, + ], + }, + { + code: `import foo from '@not-real/package/deep/path'`, + errors: [ + { + messageId: 'extraneous', + data: { packageName: '@not-real/package' }, + }, + ], + }, + { + code: `export { foo } from 'not-a-real-package'`, + errors: [ + { + messageId: 'extraneous', + data: { packageName: 'not-a-real-package' }, + }, + ], + }, + { + code: `export * from 'not-a-real-package'`, + errors: [ + { + messageId: 'extraneous', + data: { packageName: 'not-a-real-package' }, + }, + ], + }, + { + code: `const foo = require('not-a-real-package')`, + errors: [ + { + messageId: 'extraneous', + data: { packageName: 'not-a-real-package' }, + }, + ], + }, + ], + }, + { + parserOptions: { + ecmaVersion: 2020, + sourceType: 'module', + }, + }, +); diff --git a/packages/eslint-plugin-actual/lib/rules/no-extraneous-dependencies.js b/packages/eslint-plugin-actual/lib/rules/no-extraneous-dependencies.js new file mode 100644 index 0000000000..498bb07bf5 --- /dev/null +++ b/packages/eslint-plugin-actual/lib/rules/no-extraneous-dependencies.js @@ -0,0 +1,136 @@ +const fs = require('fs'); +const path = require('path'); +const Module = require('module'); + +const builtins = new Set(Module.builtinModules.flatMap(m => [m, `node:${m}`])); + +// Cache: directory path → { name, deps } | null +const pkgCache = new Map(); + +function getPackageName(source) { + if (source.startsWith('@')) { + // @scope/pkg or @scope/pkg/deep → @scope/pkg + const parts = source.split('/'); + return parts.length >= 2 ? `${parts[0]}/${parts[1]}` : null; + } + // pkg or pkg/deep → pkg + return source.split('/')[0]; +} + +function findPackageJson(dir) { + if (pkgCache.has(dir)) return pkgCache.get(dir); + + const visited = [dir]; + let current = dir; + let result = null; + + while (true) { + const pkgPath = path.join(current, 'package.json'); + try { + const content = JSON.parse(fs.readFileSync(pkgPath, 'utf8')); + if (content.name) { + result = { + name: content.name, + deps: new Set([ + ...Object.keys(content.dependencies || {}), + ...Object.keys(content.devDependencies || {}), + ]), + }; + break; + } + } catch { + // keep walking + } + const parent = path.dirname(current); + if (parent === current) break; + current = parent; + visited.push(current); + } + + for (const d of visited) { + pkgCache.set(d, result); + } + return result; +} + +function isExternalImport(source) { + if ( + source.startsWith('.') || + source.startsWith('#') || + source.startsWith('virtual:') + ) { + return false; + } + // Check builtins using the package name to handle subpaths like fs/promises + const pkgName = getPackageName(source); + if (pkgName && builtins.has(pkgName)) return false; + return true; +} + +/** @type {import('eslint').Rule.RuleModule} */ +module.exports = { + meta: { + type: 'problem', + docs: { + description: + 'Disallow importing packages not listed in dependencies or devDependencies', + }, + schema: [], + messages: { + extraneous: + '"{{packageName}}" is not listed in dependencies or devDependencies. Add it to the package.json of this workspace.', + }, + }, + + create(context) { + const filename = context.getFilename(); + const dir = path.dirname(filename); + const pkg = findPackageJson(dir); + + if (!pkg) return {}; + + function check(node, source) { + if (!source || typeof source.value !== 'string') return; + + const importSource = source.value; + if (!isExternalImport(importSource)) return; + + const packageName = getPackageName(importSource); + if (!packageName) return; + + // Allow self-references + if (packageName === pkg.name) return; + + if (!pkg.deps.has(packageName)) { + context.report({ + node: source, + messageId: 'extraneous', + data: { packageName }, + }); + } + } + + return { + ImportDeclaration(node) { + check(node, node.source); + }, + ExportNamedDeclaration(node) { + check(node, node.source); + }, + ExportAllDeclaration(node) { + check(node, node.source); + }, + CallExpression(node) { + if ( + node.callee.type === 'Identifier' && + node.callee.name === 'require' && + node.arguments.length === 1 && + node.arguments[0].type === 'Literal' && + typeof node.arguments[0].value === 'string' + ) { + check(node, node.arguments[0]); + } + }, + }; + }, +}; diff --git a/packages/loot-core/package.json b/packages/loot-core/package.json index 80729c0ad8..22333c1013 100644 --- a/packages/loot-core/package.json +++ b/packages/loot-core/package.json @@ -158,9 +158,7 @@ }, "dependencies": { "@jlongster/sql.js": "^1.6.7", - "@reduxjs/toolkit": "^2.11.2", "@rschedule/core": "^1.5.0", - "@rschedule/json-tools": "^1.5.0", "@rschedule/standard-date-adapter": "^1.5.0", "absurd-sql": "0.0.54", "adm-zip": "^0.5.16", @@ -168,14 +166,18 @@ "csv-parse": "^6.1.0", "csv-stringify": "^6.6.0", "date-fns": "^4.1.0", + "google-protobuf": "^3.21.4", "handlebars": "^4.7.9", + "hyperformula": "^3.2.0", + "lodash": "^4.18.1", "lru-cache": "^11.2.6", "memoize-one": "^6.0.0", "mitt": "^3.0.1", "promise-retry": "^2.0.1", "typescript-strict-plugin": "^2.4.4", "ua-parser-js": "^2.0.9", - "uuid": "^13.0.0" + "uuid": "^13.0.0", + "xml2js": "^0.6.2" }, "devDependencies": { "@actual-app/crdt": "workspace:*", diff --git a/upcoming-release-notes/7480.md b/upcoming-release-notes/7480.md new file mode 100644 index 0000000000..eddcbc6b4c --- /dev/null +++ b/upcoming-release-notes/7480.md @@ -0,0 +1,6 @@ +--- +category: Maintenance +authors: [MatissJanis] +--- + +Clean up installed dependencies diff --git a/yarn.lock b/yarn.lock index b836182a00..3f752f268d 100644 --- a/yarn.lock +++ b/yarn.lock @@ -42,6 +42,7 @@ __metadata: version: 0.0.0-use.local resolution: "@actual-app/ci-actions@workspace:packages/ci-actions" dependencies: + "@octokit/rest": "npm:^22.0.1" "@typescript/native-preview": "npm:^7.0.0-dev.20260309.1" extensionless: "npm:^2.0.6" gray-matter: "npm:^4.0.3" @@ -103,9 +104,7 @@ __metadata: dependencies: "@actual-app/crdt": "workspace:*" "@jlongster/sql.js": "npm:^1.6.7" - "@reduxjs/toolkit": "npm:^2.11.2" "@rschedule/core": "npm:^1.5.0" - "@rschedule/json-tools": "npm:^1.5.0" "@rschedule/standard-date-adapter": "npm:^1.5.0" "@swc/core": "npm:^1.15.18" "@types/adm-zip": "npm:^0.5.7" @@ -127,10 +126,13 @@ __metadata: date-fns: "npm:^4.1.0" fake-indexeddb: "npm:^6.2.5" fast-check: "npm:4.5.3" + google-protobuf: "npm:^3.21.4" handlebars: "npm:^4.7.9" + hyperformula: "npm:^3.2.0" i18next: "npm:^25.8.14" jest-diff: "npm:^30.2.0" jsverify: "npm:^0.8.4" + lodash: "npm:^4.18.1" lru-cache: "npm:^11.2.6" memoize-one: "npm:^6.0.0" mitt: "npm:^3.0.1" @@ -151,6 +153,7 @@ __metadata: vite-plugin-node-polyfills: "npm:^0.26.0" vite-plugin-peggy-loader: "npm:^2.0.1" vitest: "npm:^4.1.0" + xml2js: "npm:^0.6.2" yargs: "npm:^18.0.0" languageName: unknown linkType: soft @@ -242,6 +245,8 @@ __metadata: "@juggle/resize-observer": "npm:^3.4.0" "@lezer/highlight": "npm:^1.2.3" "@playwright/test": "npm:1.58.2" + "@react-aria/interactions": "npm:^3.27.0" + "@reduxjs/toolkit": "npm:^2.11.2" "@rolldown/plugin-babel": "npm:~0.1.8" "@rollup/plugin-inject": "npm:^5.0.5" "@swc/core": "npm:^1.15.18" @@ -262,19 +267,23 @@ __metadata: "@use-gesture/react": "npm:^10.3.1" "@vitejs/plugin-basic-ssl": "npm:^2.2.0" "@vitejs/plugin-react": "npm:^6.0.0" + absurd-sql: "npm:0.0.54" auto-text-size: "npm:^0.2.3" babel-plugin-react-compiler: "npm:^1.0.0" cmdk: "npm:^1.1.1" cross-env: "npm:^10.1.0" date-fns: "npm:^4.1.0" downshift: "npm:9.3.2" + html-to-image: "npm:^1.11.13" hyperformula: "npm:^3.2.0" i18next: "npm:^25.8.14" i18next-parser: "npm:^9.4.0" i18next-resources-to-backend: "npm:^1.2.1" jsdom: "npm:^27.4.0" lodash: "npm:^4.18.1" + lru-cache: "npm:^11.2.6" mdast-util-newline-to-break: "npm:^2.0.0" + memoize-one: "npm:^6.0.0" pikaday: "npm:1.8.2" promise-retry: "npm:^2.0.1" re-resizable: "npm:^6.11.2" @@ -299,6 +308,7 @@ __metadata: recharts: "npm:^3.7.0" rehype-external-links: "npm:^3.0.0" remark-gfm: "npm:^4.0.1" + rolldown: "npm:^1.0.0-rc.12" rollup-plugin-visualizer: "npm:^6.0.11" sass: "npm:^1.97.3" typescript-strict-plugin: "npm:^2.4.4" @@ -4140,6 +4150,16 @@ __metadata: languageName: node linkType: hard +"@emnapi/core@npm:1.9.2": + version: 1.9.2 + resolution: "@emnapi/core@npm:1.9.2" + dependencies: + "@emnapi/wasi-threads": "npm:1.2.1" + tslib: "npm:^2.4.0" + checksum: 10/32084861f306b405f10f3ae13d1a49fa75650bdaaa40704892c397856815fe5d3781670d2662806d39c2d8a19bb62826dd7b870a79858f7be77500d9d0d3d91a + languageName: node + linkType: hard + "@emnapi/core@npm:^1.4.3": version: 1.5.0 resolution: "@emnapi/core@npm:1.5.0" @@ -4160,6 +4180,15 @@ __metadata: languageName: node linkType: hard +"@emnapi/runtime@npm:1.9.2": + version: 1.9.2 + resolution: "@emnapi/runtime@npm:1.9.2" + dependencies: + tslib: "npm:^2.4.0" + checksum: 10/de123d6b7acdbe34bf997523be761e5ae6d8f9b3967b72e8e50ff7dd1791a2a0d2b9fb0d7d92230b0738502980ea6f947189b7c1f47814ff666515a55c6fff48 + languageName: node + linkType: hard + "@emnapi/runtime@npm:^1.4.3": version: 1.5.0 resolution: "@emnapi/runtime@npm:1.5.0" @@ -4196,6 +4225,15 @@ __metadata: languageName: node linkType: hard +"@emnapi/wasi-threads@npm:1.2.1": + version: 1.2.1 + resolution: "@emnapi/wasi-threads@npm:1.2.1" + dependencies: + tslib: "npm:^2.4.0" + checksum: 10/57cd4292be81c05d26aa886d68a9e4c449ff666e8503fed6463dfc6b64a4e4213f03c152d53296b7cda32840271e38cd33347332070658f01befeb9bf4e59f36 + languageName: node + linkType: hard + "@emotion/babel-plugin@npm:^11.13.5": version: 11.13.5 resolution: "@emotion/babel-plugin@npm:11.13.5" @@ -5381,6 +5419,18 @@ __metadata: languageName: node linkType: hard +"@napi-rs/wasm-runtime@npm:^1.1.3": + version: 1.1.3 + resolution: "@napi-rs/wasm-runtime@npm:1.1.3" + dependencies: + "@tybys/wasm-util": "npm:^0.10.1" + peerDependencies: + "@emnapi/core": ^1.7.1 + "@emnapi/runtime": ^1.7.1 + checksum: 10/a09f53dea7f5d11cbf4b4e3f10f726dd488b4a715f14f197dd619920d733e657261bb87d399628689dbe2b23b4353ddc122303d0583c4ef6cc4a5245367dfb2a + languageName: node + linkType: hard + "@neoconfetti/react@npm:^1.0.0": version: 1.0.0 resolution: "@neoconfetti/react@npm:1.0.0" @@ -5740,6 +5790,13 @@ __metadata: languageName: node linkType: hard +"@oxc-project/types@npm:=0.124.0": + version: 0.124.0 + resolution: "@oxc-project/types@npm:0.124.0" + checksum: 10/d40ca0769b19b327b89fca30c9c224aace1b696e8b4f5adc2c67ee711e17401d532fdcfe49b8903916e8749ea67b572d3c470045279e27d26ac39af7bf1fc611 + languageName: node + linkType: hard + "@oxfmt/binding-android-arm-eabi@npm:0.44.0": version: 0.44.0 resolution: "@oxfmt/binding-android-arm-eabi@npm:0.44.0" @@ -8429,6 +8486,13 @@ __metadata: languageName: node linkType: hard +"@rolldown/binding-android-arm64@npm:1.0.0-rc.15": + version: 1.0.0-rc.15 + resolution: "@rolldown/binding-android-arm64@npm:1.0.0-rc.15" + conditions: os=android & cpu=arm64 + languageName: node + linkType: hard + "@rolldown/binding-android-arm64@npm:1.0.0-rc.9": version: 1.0.0-rc.9 resolution: "@rolldown/binding-android-arm64@npm:1.0.0-rc.9" @@ -8443,6 +8507,13 @@ __metadata: languageName: node linkType: hard +"@rolldown/binding-darwin-arm64@npm:1.0.0-rc.15": + version: 1.0.0-rc.15 + resolution: "@rolldown/binding-darwin-arm64@npm:1.0.0-rc.15" + conditions: os=darwin & cpu=arm64 + languageName: node + linkType: hard + "@rolldown/binding-darwin-arm64@npm:1.0.0-rc.9": version: 1.0.0-rc.9 resolution: "@rolldown/binding-darwin-arm64@npm:1.0.0-rc.9" @@ -8457,6 +8528,13 @@ __metadata: languageName: node linkType: hard +"@rolldown/binding-darwin-x64@npm:1.0.0-rc.15": + version: 1.0.0-rc.15 + resolution: "@rolldown/binding-darwin-x64@npm:1.0.0-rc.15" + conditions: os=darwin & cpu=x64 + languageName: node + linkType: hard + "@rolldown/binding-darwin-x64@npm:1.0.0-rc.9": version: 1.0.0-rc.9 resolution: "@rolldown/binding-darwin-x64@npm:1.0.0-rc.9" @@ -8471,6 +8549,13 @@ __metadata: languageName: node linkType: hard +"@rolldown/binding-freebsd-x64@npm:1.0.0-rc.15": + version: 1.0.0-rc.15 + resolution: "@rolldown/binding-freebsd-x64@npm:1.0.0-rc.15" + conditions: os=freebsd & cpu=x64 + languageName: node + linkType: hard + "@rolldown/binding-freebsd-x64@npm:1.0.0-rc.9": version: 1.0.0-rc.9 resolution: "@rolldown/binding-freebsd-x64@npm:1.0.0-rc.9" @@ -8485,6 +8570,13 @@ __metadata: languageName: node linkType: hard +"@rolldown/binding-linux-arm-gnueabihf@npm:1.0.0-rc.15": + version: 1.0.0-rc.15 + resolution: "@rolldown/binding-linux-arm-gnueabihf@npm:1.0.0-rc.15" + conditions: os=linux & cpu=arm + languageName: node + linkType: hard + "@rolldown/binding-linux-arm-gnueabihf@npm:1.0.0-rc.9": version: 1.0.0-rc.9 resolution: "@rolldown/binding-linux-arm-gnueabihf@npm:1.0.0-rc.9" @@ -8499,6 +8591,13 @@ __metadata: languageName: node linkType: hard +"@rolldown/binding-linux-arm64-gnu@npm:1.0.0-rc.15": + version: 1.0.0-rc.15 + resolution: "@rolldown/binding-linux-arm64-gnu@npm:1.0.0-rc.15" + conditions: os=linux & cpu=arm64 & libc=glibc + languageName: node + linkType: hard + "@rolldown/binding-linux-arm64-gnu@npm:1.0.0-rc.9": version: 1.0.0-rc.9 resolution: "@rolldown/binding-linux-arm64-gnu@npm:1.0.0-rc.9" @@ -8513,6 +8612,13 @@ __metadata: languageName: node linkType: hard +"@rolldown/binding-linux-arm64-musl@npm:1.0.0-rc.15": + version: 1.0.0-rc.15 + resolution: "@rolldown/binding-linux-arm64-musl@npm:1.0.0-rc.15" + conditions: os=linux & cpu=arm64 & libc=musl + languageName: node + linkType: hard + "@rolldown/binding-linux-arm64-musl@npm:1.0.0-rc.9": version: 1.0.0-rc.9 resolution: "@rolldown/binding-linux-arm64-musl@npm:1.0.0-rc.9" @@ -8527,6 +8633,13 @@ __metadata: languageName: node linkType: hard +"@rolldown/binding-linux-ppc64-gnu@npm:1.0.0-rc.15": + version: 1.0.0-rc.15 + resolution: "@rolldown/binding-linux-ppc64-gnu@npm:1.0.0-rc.15" + conditions: os=linux & cpu=ppc64 & libc=glibc + languageName: node + linkType: hard + "@rolldown/binding-linux-ppc64-gnu@npm:1.0.0-rc.9": version: 1.0.0-rc.9 resolution: "@rolldown/binding-linux-ppc64-gnu@npm:1.0.0-rc.9" @@ -8541,6 +8654,13 @@ __metadata: languageName: node linkType: hard +"@rolldown/binding-linux-s390x-gnu@npm:1.0.0-rc.15": + version: 1.0.0-rc.15 + resolution: "@rolldown/binding-linux-s390x-gnu@npm:1.0.0-rc.15" + conditions: os=linux & cpu=s390x & libc=glibc + languageName: node + linkType: hard + "@rolldown/binding-linux-s390x-gnu@npm:1.0.0-rc.9": version: 1.0.0-rc.9 resolution: "@rolldown/binding-linux-s390x-gnu@npm:1.0.0-rc.9" @@ -8555,6 +8675,13 @@ __metadata: languageName: node linkType: hard +"@rolldown/binding-linux-x64-gnu@npm:1.0.0-rc.15": + version: 1.0.0-rc.15 + resolution: "@rolldown/binding-linux-x64-gnu@npm:1.0.0-rc.15" + conditions: os=linux & cpu=x64 & libc=glibc + languageName: node + linkType: hard + "@rolldown/binding-linux-x64-gnu@npm:1.0.0-rc.9": version: 1.0.0-rc.9 resolution: "@rolldown/binding-linux-x64-gnu@npm:1.0.0-rc.9" @@ -8569,6 +8696,13 @@ __metadata: languageName: node linkType: hard +"@rolldown/binding-linux-x64-musl@npm:1.0.0-rc.15": + version: 1.0.0-rc.15 + resolution: "@rolldown/binding-linux-x64-musl@npm:1.0.0-rc.15" + conditions: os=linux & cpu=x64 & libc=musl + languageName: node + linkType: hard + "@rolldown/binding-linux-x64-musl@npm:1.0.0-rc.9": version: 1.0.0-rc.9 resolution: "@rolldown/binding-linux-x64-musl@npm:1.0.0-rc.9" @@ -8583,6 +8717,13 @@ __metadata: languageName: node linkType: hard +"@rolldown/binding-openharmony-arm64@npm:1.0.0-rc.15": + version: 1.0.0-rc.15 + resolution: "@rolldown/binding-openharmony-arm64@npm:1.0.0-rc.15" + conditions: os=openharmony & cpu=arm64 + languageName: node + linkType: hard + "@rolldown/binding-openharmony-arm64@npm:1.0.0-rc.9": version: 1.0.0-rc.9 resolution: "@rolldown/binding-openharmony-arm64@npm:1.0.0-rc.9" @@ -8599,6 +8740,17 @@ __metadata: languageName: node linkType: hard +"@rolldown/binding-wasm32-wasi@npm:1.0.0-rc.15": + version: 1.0.0-rc.15 + resolution: "@rolldown/binding-wasm32-wasi@npm:1.0.0-rc.15" + dependencies: + "@emnapi/core": "npm:1.9.2" + "@emnapi/runtime": "npm:1.9.2" + "@napi-rs/wasm-runtime": "npm:^1.1.3" + conditions: cpu=wasm32 + languageName: node + linkType: hard + "@rolldown/binding-wasm32-wasi@npm:1.0.0-rc.9": version: 1.0.0-rc.9 resolution: "@rolldown/binding-wasm32-wasi@npm:1.0.0-rc.9" @@ -8615,6 +8767,13 @@ __metadata: languageName: node linkType: hard +"@rolldown/binding-win32-arm64-msvc@npm:1.0.0-rc.15": + version: 1.0.0-rc.15 + resolution: "@rolldown/binding-win32-arm64-msvc@npm:1.0.0-rc.15" + conditions: os=win32 & cpu=arm64 + languageName: node + linkType: hard + "@rolldown/binding-win32-arm64-msvc@npm:1.0.0-rc.9": version: 1.0.0-rc.9 resolution: "@rolldown/binding-win32-arm64-msvc@npm:1.0.0-rc.9" @@ -8629,6 +8788,13 @@ __metadata: languageName: node linkType: hard +"@rolldown/binding-win32-x64-msvc@npm:1.0.0-rc.15": + version: 1.0.0-rc.15 + resolution: "@rolldown/binding-win32-x64-msvc@npm:1.0.0-rc.15" + conditions: os=win32 & cpu=x64 + languageName: node + linkType: hard + "@rolldown/binding-win32-x64-msvc@npm:1.0.0-rc.9": version: 1.0.0-rc.9 resolution: "@rolldown/binding-win32-x64-msvc@npm:1.0.0-rc.9" @@ -8659,6 +8825,13 @@ __metadata: languageName: node linkType: hard +"@rolldown/pluginutils@npm:1.0.0-rc.15": + version: 1.0.0-rc.15 + resolution: "@rolldown/pluginutils@npm:1.0.0-rc.15" + checksum: 10/528e6c4ebe43cc64daa1b068b23aac3df5de1aa152842f842c00d343dc4505603133f1f4e95c761551bca42fcf8506063d955c27d3b7ca748b6426d11d1e9fb5 + languageName: node + linkType: hard + "@rolldown/pluginutils@npm:1.0.0-rc.7": version: 1.0.0-rc.7 resolution: "@rolldown/pluginutils@npm:1.0.0-rc.7" @@ -8928,15 +9101,6 @@ __metadata: languageName: node linkType: hard -"@rschedule/json-tools@npm:^1.5.0": - version: 1.5.0 - resolution: "@rschedule/json-tools@npm:1.5.0" - peerDependencies: - "@rschedule/core": ^1.5.0 - checksum: 10/aa9fa497f91bceb65983c9917fb0fde460d48cb21538859f482e00a0c677afa8ef5b5d7b4c614eceb5a32c542fc23fc105578cb37905f387d379c8e462a3c370 - languageName: node - linkType: hard - "@rschedule/standard-date-adapter@npm:^1.5.0": version: 1.5.0 resolution: "@rschedule/standard-date-adapter@npm:1.5.0" @@ -11809,6 +11973,7 @@ __metadata: prompts: "npm:^2.4.2" ts-node: "npm:^10.9.2" typescript: "npm:^5.9.3" + vitest: "npm:^4.1.0" languageName: unknown linkType: soft @@ -15437,7 +15602,9 @@ __metadata: dependencies: "@actual-app/core": "workspace:*" "@actual-app/sync-server": "workspace:*" + "@actual-app/web": "workspace:*" "@electron/notarize": "npm:3.1.1" + "@electron/rebuild": "npm:^4.0.3" "@playwright/test": "npm:1.58.2" "@types/copyfiles": "npm:^2" "@types/fs-extra": "npm:^11" @@ -26359,6 +26526,64 @@ __metadata: languageName: node linkType: hard +"rolldown@npm:^1.0.0-rc.12": + version: 1.0.0-rc.15 + resolution: "rolldown@npm:1.0.0-rc.15" + dependencies: + "@oxc-project/types": "npm:=0.124.0" + "@rolldown/binding-android-arm64": "npm:1.0.0-rc.15" + "@rolldown/binding-darwin-arm64": "npm:1.0.0-rc.15" + "@rolldown/binding-darwin-x64": "npm:1.0.0-rc.15" + "@rolldown/binding-freebsd-x64": "npm:1.0.0-rc.15" + "@rolldown/binding-linux-arm-gnueabihf": "npm:1.0.0-rc.15" + "@rolldown/binding-linux-arm64-gnu": "npm:1.0.0-rc.15" + "@rolldown/binding-linux-arm64-musl": "npm:1.0.0-rc.15" + "@rolldown/binding-linux-ppc64-gnu": "npm:1.0.0-rc.15" + "@rolldown/binding-linux-s390x-gnu": "npm:1.0.0-rc.15" + "@rolldown/binding-linux-x64-gnu": "npm:1.0.0-rc.15" + "@rolldown/binding-linux-x64-musl": "npm:1.0.0-rc.15" + "@rolldown/binding-openharmony-arm64": "npm:1.0.0-rc.15" + "@rolldown/binding-wasm32-wasi": "npm:1.0.0-rc.15" + "@rolldown/binding-win32-arm64-msvc": "npm:1.0.0-rc.15" + "@rolldown/binding-win32-x64-msvc": "npm:1.0.0-rc.15" + "@rolldown/pluginutils": "npm:1.0.0-rc.15" + dependenciesMeta: + "@rolldown/binding-android-arm64": + optional: true + "@rolldown/binding-darwin-arm64": + optional: true + "@rolldown/binding-darwin-x64": + optional: true + "@rolldown/binding-freebsd-x64": + optional: true + "@rolldown/binding-linux-arm-gnueabihf": + optional: true + "@rolldown/binding-linux-arm64-gnu": + optional: true + "@rolldown/binding-linux-arm64-musl": + optional: true + "@rolldown/binding-linux-ppc64-gnu": + optional: true + "@rolldown/binding-linux-s390x-gnu": + optional: true + "@rolldown/binding-linux-x64-gnu": + optional: true + "@rolldown/binding-linux-x64-musl": + optional: true + "@rolldown/binding-openharmony-arm64": + optional: true + "@rolldown/binding-wasm32-wasi": + optional: true + "@rolldown/binding-win32-arm64-msvc": + optional: true + "@rolldown/binding-win32-x64-msvc": + optional: true + bin: + rolldown: bin/cli.mjs + checksum: 10/cc07a103297573690bad1469e96e282230f9eb1acc4e22bf3318294bf5b5221d475d1c0822be6fe4958c5618983cac70fb0155afe510ab51516a053564c9304a + languageName: node + linkType: hard + "rollup-plugin-visualizer@npm:^6.0.11": version: 6.0.11 resolution: "rollup-plugin-visualizer@npm:6.0.11"