From 3a22f1a15325facdf750684b00420222c4323a97 Mon Sep 17 00:00:00 2001 From: Matiss Janis Aboltins Date: Thu, 12 Mar 2026 17:43:39 +0000 Subject: [PATCH] refactor(api): fix cyclic dependencies (#6809) * refactor(api): defineConfig vitest, api-helpers, drop vite.api build - Wrap api vitest.config with defineConfig for typing/IDE - Add loot-core api-helpers, use in YNAB4/YNAB5 importers - Remove vite.api.config, build-api, injected.js; simplify api package * refactor(api): update package structure and build scripts - Change main entry point and types definition paths in package.json to reflect new structure. - Simplify build script by removing migration and default database copy commands. - Adjust tsconfig.dist.json to maintain declaration directory. - Add typings for external modules in a new typings.ts file. - Update comments in schedules.ts to improve clarity and maintainability. * chore(api): update dependencies and build configuration - Replace tsc-alias with rollup-plugin-visualizer in package.json. - Update build script to use vite for building the API package. - Add vite configuration file for improved build process and visualization. - Adjust tsconfig.dist.json to exclude additional configuration files from the build. * fix(api): update visualizer output path in vite configuration - Change the output filename for the visualizer plugin from 'dist/stats.json' to 'app/stats.json' to align with the new directory structure. * refactor(api): streamline Vite configuration and remove vitest.config.ts - Remove vitest.config.ts as its configuration is now integrated into vite.config.ts. - Update vite.config.ts to include sourcemap generation and adjust CRDT path resolution. - Modify vitest.setup.ts to correct the import path for the CRDT proto file. * feat(api): enhance build scripts and add file system utilities - Update build scripts in package.json to include separate commands for building node, migrations, and default database. - Introduce a new file system utility module in loot-core to handle file operations such as reading, writing, and directory management. - Implement error handling and logging for file operations to improve robustness. * Refactor typecheck script in api package and enhance api-helpers with new schedule and rule update functions. The typecheck command was simplified by removing the strict check, and new API methods for creating schedules and updating rules were added to improve functionality. * Refactor API integration in loot-core by removing api-helpers and directly invoking handlers. Update typecheck script in api package to include strict checks, and refine TypeScript configurations across multiple packages for improved type safety and build processes. * Refactor imports and enhance code readability across multiple files in loot-core. Simplified import statements in the API and adjusted formatting in YNAB importers for consistency. Updated type annotations to improve type safety and maintainability. * Refactor handler invocation in YNAB importers to use the new send function from main-app. This change improves code consistency and readability by standardizing the method of invoking handlers across different modules. * Refactor schedule configuration in loot-core to enhance type safety by introducing a new ScheduleRuleOptions type. This change improves the clarity of the recurring schedule configuration and ensures better type checking for frequency and interval properties. * Update TypeScript configuration in api package to include path mapping for loot-core. This change enhances module resolution and improves type safety by allowing direct imports from the loot-core source directory. * Update TypeScript configuration in api package to reposition the typescript-strict-plugin entry. This change improves the organization of the tsconfig.json file while maintaining the existing path mapping for loot-core, ensuring consistent type checking across the project. * Update TypeScript configurations across multiple packages to enable noEmit option. This change enhances build processes by preventing unnecessary output files during compilation. Additionally, remove the obsolete tsconfig.api.json file from loot-core to streamline project structure. * Update TypeScript configuration in sync-server package to enable noEmit option. This change allows for the generation of output files during compilation, facilitating the build process. * Update api package configuration to streamline build process and enhance type safety. Removed unnecessary build scripts, integrated vite-plugin-dts for type declaration generation, and added migration and default database copying functionality. Adjusted vitest setup to comment out CRDT proto file import for improved test isolation. * Update TypeScript configurations in desktop-client and desktop-electron packages to enable noEmit option, allowing for output file generation during compilation. Additionally, add ts-strict-ignore comments in YNAB importers to suppress strict type checking, improving compatibility with embedded API usage. * Refactor api package configuration to update type declaration paths and enhance build process. Changed type definitions reference in package.json, streamlined tsconfig.json exclusions, and added functionality to copy inlined types during the build. Removed obsolete vitest setup file for improved test isolation. * Revert to solution without types * Update TypeScript configuration in API package to use ES2022 module and bundler resolution. This change enhances compatibility with modern JavaScript features and improves the build process. * Update yarn.lock and API package to enhance TypeScript build process and add new dependencies * Refactor inline-loot-core-types script to streamline TypeScript declaration handling and improve output organization. Remove legacy code and directly copy loot-core declaration tree, updating index.d.ts to reference local imports. * Add internal export to API and enhance Vite configuration for migration handling * Update Vite configuration in API package to target Node 18, enhancing compatibility with the latest Node features. * Enhance inline-loot-core-types script to improve TypeScript declaration handling by separating source and typings directories. Update the copy process to include emitted typings, ensuring no declarations are dropped and maintaining better organization of loot-core types. * Enhance migration handling by allowing both .sql and .js files to be copied during the migration process. Refactor file system operations in loot-core to improve error handling and streamline file management, including new methods for reading, writing, and removing files and directories. * Refactor rootPath determination in Electron file system module by removing legacy case for 'bundle.api.js'. This simplifies the path management for the Electron app. * Update API tests to mock file system paths for migration handling and change Vite configuration to target Node 20 for improved compatibility. * Add promise-retry dependency to loot-core package and update yarn.lock * Fix lint * Refactor build script order in package.json for improved execution flow * Feedback: API changes for "internal" --- package.json | 6 +- packages/api/index.ts | 34 +- packages/api/injected.js | 7 - packages/api/methods.test.ts | 19 + packages/api/methods.ts | 5 +- packages/api/package.json | 18 +- .../api/scripts/inline-loot-core-types.mjs | 60 +++ packages/api/tsconfig.json | 10 +- packages/api/typings.ts | 2 + packages/api/utils.ts | 8 +- packages/api/vite.config.ts | 99 ++++ packages/api/vitest.config.ts | 10 - packages/loot-core/bin/build-api | 11 - packages/loot-core/package.json | 3 +- .../src/platform/server/fs/index.api.ts | 200 ++++++- .../src/platform/server/fs/index.electron.ts | 3 - packages/loot-core/src/server/main.ts | 4 - .../src/server/migrate/migrations.ts | 28 +- packages/loot-core/vite.api.config.ts | 58 --- upcoming-release-notes/6809.md | 6 + yarn.lock | 489 +++++++++++++++--- 21 files changed, 842 insertions(+), 238 deletions(-) delete mode 100644 packages/api/injected.js create mode 100644 packages/api/scripts/inline-loot-core-types.mjs create mode 100644 packages/api/typings.ts create mode 100644 packages/api/vite.config.ts delete mode 100644 packages/api/vitest.config.ts delete mode 100755 packages/loot-core/bin/build-api delete mode 100644 packages/loot-core/vite.api.config.ts create mode 100644 upcoming-release-notes/6809.md diff --git a/package.json b/package.json index 0d53db6560..f8a1a91d45 100644 --- a/package.json +++ b/package.json @@ -54,10 +54,10 @@ "vrt:docker": "./bin/run-vrt", "rebuild-electron": "./node_modules/.bin/electron-rebuild -m ./packages/loot-core", "rebuild-node": "yarn workspace loot-core rebuild", - "lint": "yarn workspace @actual-app/api clean && oxfmt --check . && oxlint --type-aware", - "lint:fix": "yarn workspace @actual-app/api clean && oxfmt . && oxlint --fix --type-aware", + "lint": "oxfmt --check . && oxlint --type-aware", + "lint:fix": "oxfmt . && oxlint --fix --type-aware", "install:server": "yarn workspaces focus @actual-app/sync-server --production", - "typecheck": "yarn workspace @actual-app/api clean && tsc -b && tsc -p tsconfig.root.json --noEmit && lage typecheck", + "typecheck": "tsc -b && tsc -p tsconfig.root.json --noEmit && lage typecheck", "jq": "./node_modules/node-jq/bin/jq", "prepare": "husky" }, diff --git a/packages/api/index.ts b/packages/api/index.ts index f265d84e03..38e9d5f723 100644 --- a/packages/api/index.ts +++ b/packages/api/index.ts @@ -3,26 +3,18 @@ import type { RequestInit as FetchInit, } from 'node-fetch'; -// loot-core types -import type { InitConfig } from 'loot-core/server/main'; +import { init as initLootCore } from 'loot-core/server/main'; +import type { InitConfig, lib } from 'loot-core/server/main'; -// oxlint-disable-next-line typescript/ban-ts-comment -// @ts-ignore: bundle not available until we build it -import * as bundle from './app/bundle.api.js'; -import * as injected from './injected'; import { validateNodeVersion } from './validateNodeVersion'; -let actualApp: null | typeof bundle.lib; -export const internal = bundle.lib; - export * from './methods'; export * as utils from './utils'; -export async function init(config: InitConfig = {}) { - if (actualApp) { - return; - } +/** @deprecated Please use return value of `init` instead */ +export let internal: typeof lib | null = null; +export async function init(config: InitConfig = {}) { validateNodeVersion(); if (!globalThis.fetch) { @@ -33,21 +25,19 @@ export async function init(config: InitConfig = {}) { }; } - await bundle.init(config); - actualApp = bundle.lib; - - injected.override(bundle.lib.send); - return bundle.lib; + internal = await initLootCore(config); + return internal; } export async function shutdown() { - if (actualApp) { + if (internal) { try { - await actualApp.send('sync'); + await internal.send('sync'); } catch { // most likely that no budget is loaded, so the sync failed } - await actualApp.send('close-budget'); - actualApp = null; + + await internal.send('close-budget'); + internal = null; } } diff --git a/packages/api/injected.js b/packages/api/injected.js deleted file mode 100644 index 682ccfd4f0..0000000000 --- a/packages/api/injected.js +++ /dev/null @@ -1,7 +0,0 @@ -// TODO: comment on why it works this way - -export let send; - -export function override(sendImplementation) { - send = sendImplementation; -} diff --git a/packages/api/methods.test.ts b/packages/api/methods.test.ts index f1fffe8df1..5bb180b8e1 100644 --- a/packages/api/methods.test.ts +++ b/packages/api/methods.test.ts @@ -1,10 +1,29 @@ import * as fs from 'fs/promises'; import * as path from 'path'; +import { vi } from 'vitest'; + import type { RuleEntity } from 'loot-core/types/models'; import * as api from './index'; +// In tests we run from source; loot-core's API fs uses __dirname (for the built dist/). +// Mock the fs so path constants point at loot-core package root where migrations live. +vi.mock( + '../loot-core/src/platform/server/fs/index.api', + async importOriginal => { + const actual = (await importOriginal()) as Record; + const pathMod = await import('path'); + const lootCoreRoot = pathMod.join(__dirname, '..', 'loot-core'); + return { + ...actual, + migrationsPath: pathMod.join(lootCoreRoot, 'migrations'), + bundledDatabasePath: pathMod.join(lootCoreRoot, 'default-db.sqlite'), + demoBudgetPath: pathMod.join(lootCoreRoot, 'demo-budget'), + }; + }, +); + const budgetName = 'test-budget'; global.IS_TESTING = true; diff --git a/packages/api/methods.ts b/packages/api/methods.ts index eef0198b9c..3ba5916115 100644 --- a/packages/api/methods.ts +++ b/packages/api/methods.ts @@ -7,6 +7,7 @@ import type { APIScheduleEntity, APITagEntity, } from 'loot-core/server/api-models'; +import { lib } from 'loot-core/server/main'; import type { Query } from 'loot-core/shared/query'; import type { ImportTransactionsOpts } from 'loot-core/types/api-handlers'; import type { Handlers } from 'loot-core/types/handlers'; @@ -16,15 +17,13 @@ import type { TransactionEntity, } from 'loot-core/types/models'; -import * as injected from './injected'; - export { q } from './app/query'; function send( name: K, args?: Parameters[0], ): Promise>> { - return injected.send(name, args); + return lib.send(name, args); } export async function runImport( diff --git a/packages/api/package.json b/packages/api/package.json index 6310fddd85..9406b0dbba 100644 --- a/packages/api/package.json +++ b/packages/api/package.json @@ -10,27 +10,25 @@ "main": "dist/index.js", "types": "@types/index.d.ts", "scripts": { - "build:app": "yarn workspace loot-core build:api", - "build:crdt": "yarn workspace @actual-app/crdt build", - "build:node": "tsc && tsc-alias", - "build:migrations": "cp migrations/*.sql dist/migrations", - "build:default-db": "cp default-db.sqlite dist/", - "build": "yarn run clean && yarn run build:app && yarn run build:node && yarn run build:migrations && yarn run build:default-db", - "test": "yarn run clean && yarn run build:app && yarn run build:crdt && vitest --run", - "clean": "rm -rf dist @types", - "typecheck": "yarn build && tsc --noEmit && tsc-strict" + "build": "yarn workspace loot-core exec tsc && vite build && node scripts/inline-loot-core-types.mjs", + "test": "vitest --run", + "typecheck": "tsc --noEmit && tsc-strict" }, "dependencies": { "@actual-app/crdt": "workspace:^", "better-sqlite3": "^12.6.2", "compare-versions": "^6.1.1", + "loot-core": "workspace:^", "node-fetch": "^3.3.2", "uuid": "^13.0.0" }, "devDependencies": { - "tsc-alias": "^1.8.16", + "rollup-plugin-visualizer": "^6.0.5", "typescript": "^5.9.3", "typescript-strict-plugin": "^2.4.4", + "vite": "^7.3.1", + "vite-plugin-dts": "^4.5.4", + "vite-plugin-peggy-loader": "^2.0.1", "vitest": "^4.0.18" }, "engines": { diff --git a/packages/api/scripts/inline-loot-core-types.mjs b/packages/api/scripts/inline-loot-core-types.mjs new file mode 100644 index 0000000000..54f221ef60 --- /dev/null +++ b/packages/api/scripts/inline-loot-core-types.mjs @@ -0,0 +1,60 @@ +/** + * Post-build script: copies loot-core declaration tree into @types/loot-core + * and rewrites index.d.ts to reference it so the published package is self-contained. + * Run after vite build; requires loot-core declarations (yarn workspace loot-core exec tsc). + */ +import fs from 'fs'; +import path from 'path'; +import { fileURLToPath } from 'url'; + +const __dirname = path.dirname(fileURLToPath(import.meta.url)); +const apiRoot = path.resolve(__dirname, '..'); +const typesDir = path.join(apiRoot, '@types'); +const indexDts = path.join(typesDir, 'index.d.ts'); +const lootCoreDeclRoot = path.resolve(apiRoot, '../loot-core/lib-dist/decl'); +const lootCoreDeclSrc = path.join(lootCoreDeclRoot, 'src'); +const lootCoreDeclTypings = path.join(lootCoreDeclRoot, 'typings'); +const lootCoreTypesDir = path.join(typesDir, 'loot-core'); + +function main() { + if (!fs.existsSync(indexDts)) { + console.error('Missing @types/index.d.ts; run vite build first.'); + process.exit(1); + } + if (!fs.existsSync(lootCoreDeclSrc)) { + console.error( + 'Missing loot-core declarations; run: yarn workspace loot-core exec tsc', + ); + process.exit(1); + } + + // Remove existing loot-core output (dir or legacy single file) + if (fs.existsSync(lootCoreTypesDir)) { + fs.rmSync(lootCoreTypesDir, { recursive: true }); + } + const legacyDts = path.join(typesDir, 'loot-core.d.ts'); + if (fs.existsSync(legacyDts)) { + fs.rmSync(legacyDts); + } + + // Copy declaration tree: src (main exports) plus emitted typings so no declarations are dropped + fs.cpSync(lootCoreDeclSrc, lootCoreTypesDir, { recursive: true }); + if (fs.existsSync(lootCoreDeclTypings)) { + fs.cpSync(lootCoreDeclTypings, path.join(lootCoreTypesDir, 'typings'), { + recursive: true, + }); + } + + // Rewrite index.d.ts: remove reference, point imports at local ./loot-core/ + let indexContent = fs.readFileSync(indexDts, 'utf8'); + indexContent = indexContent.replace( + /\/\/\/ \n?/, + '', + ); + indexContent = indexContent + .replace(/'loot-core\//g, "'./loot-core/") + .replace(/"loot-core\//g, '"./loot-core/'); + fs.writeFileSync(indexDts, indexContent, 'utf8'); +} + +main(); diff --git a/packages/api/tsconfig.json b/packages/api/tsconfig.json index 69ea5e9204..dc92789cf3 100644 --- a/packages/api/tsconfig.json +++ b/packages/api/tsconfig.json @@ -5,8 +5,8 @@ // Using ES2021 because that's the newest version where // the latest Node 16.x release supports all of the features "target": "ES2021", - "module": "CommonJS", - "moduleResolution": "node10", + "module": "es2022", + "moduleResolution": "bundler", "noEmit": false, "declaration": true, "declarationMap": true, @@ -14,13 +14,9 @@ "rootDir": ".", "declarationDir": "@types", "tsBuildInfoFile": "dist/.tsbuildinfo", - "paths": { - // TEMPORARY - "loot-core/*": ["../loot-core/src/*"] - }, "plugins": [{ "name": "typescript-strict-plugin", "paths": ["."] }] }, "references": [{ "path": "../crdt" }, { "path": "../loot-core" }], "include": ["."], - "exclude": ["**/node_modules/*", "dist", "@types", "*.test.ts"] + "exclude": ["**/node_modules/*", "dist", "@types", "*.test.ts", "*.config.ts"] } diff --git a/packages/api/typings.ts b/packages/api/typings.ts new file mode 100644 index 0000000000..6a00390700 --- /dev/null +++ b/packages/api/typings.ts @@ -0,0 +1,2 @@ +declare module 'hyperformula/i18n/languages/enUS'; +declare module '*.pegjs'; diff --git a/packages/api/utils.ts b/packages/api/utils.ts index dfd3c5ca41..0977cc34e1 100644 --- a/packages/api/utils.ts +++ b/packages/api/utils.ts @@ -1,6 +1,4 @@ -// oxlint-disable-next-line typescript/ban-ts-comment -// @ts-ignore: bundle not available until we build it -import * as bundle from './app/bundle.api.js'; +import { lib } from 'loot-core/server/main'; -export const amountToInteger = bundle.lib.amountToInteger; -export const integerToAmount = bundle.lib.integerToAmount; +export const amountToInteger = lib.amountToInteger; +export const integerToAmount = lib.integerToAmount; diff --git a/packages/api/vite.config.ts b/packages/api/vite.config.ts new file mode 100644 index 0000000000..2e4d88a65c --- /dev/null +++ b/packages/api/vite.config.ts @@ -0,0 +1,99 @@ +import fs from 'fs'; +import path from 'path'; + +import { visualizer } from 'rollup-plugin-visualizer'; +import { defineConfig } from 'vite'; +import dts from 'vite-plugin-dts'; +import peggyLoader from 'vite-plugin-peggy-loader'; + +const lootCoreRoot = path.resolve(__dirname, '../loot-core'); +const distDir = path.resolve(__dirname, 'dist'); +const typesDir = path.resolve(__dirname, '@types'); + +function cleanOutputDirs() { + return { + name: 'clean-output-dirs', + buildStart() { + if (fs.existsSync(distDir)) fs.rmSync(distDir, { recursive: true }); + if (fs.existsSync(typesDir)) fs.rmSync(typesDir, { recursive: true }); + }, + }; +} + +function copyMigrationsAndDefaultDb() { + return { + name: 'copy-migrations-and-default-db', + closeBundle() { + const migrationsSrc = path.join(lootCoreRoot, 'migrations'); + const defaultDbPath = path.join(lootCoreRoot, 'default-db.sqlite'); + + if (!fs.existsSync(migrationsSrc)) { + throw new Error(`migrations directory not found at ${migrationsSrc}`); + } + const migrationsStat = fs.statSync(migrationsSrc); + if (!migrationsStat.isDirectory()) { + throw new Error(`migrations path is not a directory: ${migrationsSrc}`); + } + + const migrationsDest = path.join(distDir, 'migrations'); + fs.mkdirSync(migrationsDest, { recursive: true }); + for (const name of fs.readdirSync(migrationsSrc)) { + if (name.endsWith('.sql') || name.endsWith('.js')) { + fs.copyFileSync( + path.join(migrationsSrc, name), + path.join(migrationsDest, name), + ); + } + } + + if (!fs.existsSync(defaultDbPath)) { + throw new Error(`default-db.sqlite not found at ${defaultDbPath}`); + } + fs.copyFileSync(defaultDbPath, path.join(distDir, 'default-db.sqlite')); + }, + }; +} + +export default defineConfig({ + ssr: { noExternal: true, external: ['better-sqlite3'] }, + build: { + ssr: true, + target: 'node20', + outDir: distDir, + emptyOutDir: true, + sourcemap: true, + lib: { + entry: path.resolve(__dirname, 'index.ts'), + formats: ['cjs'], + fileName: () => 'index.js', + }, + }, + plugins: [ + cleanOutputDirs(), + peggyLoader(), + dts({ + tsconfigPath: path.resolve(__dirname, 'tsconfig.json'), + outDir: path.resolve(__dirname, '@types'), + rollupTypes: true, + }), + copyMigrationsAndDefaultDb(), + visualizer({ template: 'raw-data', filename: 'app/stats.json' }), + ], + resolve: { + extensions: ['.api.ts', '.js', '.ts', '.tsx', '.json'], + alias: [ + { + find: /^@actual-app\/crdt(\/.*)?$/, + replacement: path.resolve(__dirname, '../crdt/src') + '$1', + }, + ], + }, + test: { + globals: true, + onConsoleLog(log: string, type: 'stdout' | 'stderr'): boolean | void { + // print only console.error + return type === 'stderr'; + }, + maxWorkers: 2, + }, +}); diff --git a/packages/api/vitest.config.ts b/packages/api/vitest.config.ts deleted file mode 100644 index c34c49babe..0000000000 --- a/packages/api/vitest.config.ts +++ /dev/null @@ -1,10 +0,0 @@ -export default { - test: { - globals: true, - onConsoleLog(log: string, type: 'stdout' | 'stderr'): boolean | void { - // print only console.error - return type === 'stderr'; - }, - maxWorkers: 2, - }, -}; diff --git a/packages/loot-core/bin/build-api b/packages/loot-core/bin/build-api deleted file mode 100755 index d6667fb415..0000000000 --- a/packages/loot-core/bin/build-api +++ /dev/null @@ -1,11 +0,0 @@ -#!/bin/bash - -set -euo pipefail - -cd "$(dirname "$0")/.." || exit 1 -ROOT="$(pwd -P)" - -# Emit declarations to lib-dist/decl so api package (and tsc -b) can consume them -yarn tsc -p tsconfig.json -yarn vite build --config ./vite.api.config.ts -./bin/copy-migrations ../api diff --git a/packages/loot-core/package.json b/packages/loot-core/package.json index c3a82ecbb2..53efd4772d 100644 --- a/packages/loot-core/package.json +++ b/packages/loot-core/package.json @@ -55,7 +55,6 @@ "scripts": { "build:node": "cross-env NODE_ENV=production vite build --config ./vite.desktop.config.ts", "watch:node": "cross-env NODE_ENV=development vite build --config ./vite.desktop.config.ts --watch", - "build:api": "cross-env NODE_ENV=development ./bin/build-api", "build:browser": "cross-env NODE_ENV=production ./bin/build-browser", "watch:browser": "cross-env NODE_ENV=development ./bin/build-browser", "generate:i18n": "i18next", @@ -82,6 +81,7 @@ "md5": "^2.3.0", "memoize-one": "^6.0.0", "mitt": "^3.0.1", + "promise-retry": "^2.0.1", "slash": "5.1.0", "typescript": "^5.9.3", "typescript-strict-plugin": "^2.4.4", @@ -89,7 +89,6 @@ "uuid": "^13.0.0" }, "devDependencies": { - "@actual-app/api": "workspace:^", "@actual-app/crdt": "workspace:^", "@swc/core": "^1.15.11", "@types/adm-zip": "^0.5.7", diff --git a/packages/loot-core/src/platform/server/fs/index.api.ts b/packages/loot-core/src/platform/server/fs/index.api.ts index 1498cc1767..f83223b9b8 100644 --- a/packages/loot-core/src/platform/server/fs/index.api.ts +++ b/packages/loot-core/src/platform/server/fs/index.api.ts @@ -1,2 +1,198 @@ -// oxlint-disable-next-line no-restricted-imports -export * from './index.electron'; +// @ts-strict-ignore +import * as fs from 'fs'; +import * as path from 'path'; + +import promiseRetry from 'promise-retry'; + +import { logger } from '../log'; + +import type * as T from './index'; + +export { getDocumentDir, getBudgetDir, _setDocumentDir } from './shared'; + +export const init: typeof T.init = async () => { + // Nothing to do +}; + +export const getDataDir: typeof T.getDataDir = () => { + if (!process.env.ACTUAL_DATA_DIR) { + throw new Error('ACTUAL_DATA_DIR env variable is required'); + } + return process.env.ACTUAL_DATA_DIR; +}; + +export const bundledDatabasePath: typeof T.bundledDatabasePath = path.join( + __dirname, + 'default-db.sqlite', +); + +export const migrationsPath: typeof T.migrationsPath = path.join( + __dirname, + 'migrations', +); + +export const demoBudgetPath: typeof T.demoBudgetPath = path.join( + __dirname, + 'demo-budget', +); + +export const join: typeof T.join = (...args: Parameters) => + path.join(...args); + +export const basename: typeof T.basename = filepath => path.basename(filepath); + +export const listDir: typeof T.listDir = filepath => + new Promise((resolve, reject) => { + fs.readdir(filepath, (err, files) => { + if (err) { + reject(err); + } else { + resolve(files); + } + }); + }); + +export const exists: typeof T.exists = filepath => + new Promise(resolve => { + fs.access(filepath, fs.constants.F_OK, err => { + return resolve(!err); + }); + }); + +export const mkdir: typeof T.mkdir = filepath => + new Promise((resolve, reject) => { + fs.mkdir(filepath, err => { + if (err) { + reject(err); + } else { + resolve(undefined); + } + }); + }); + +export const size: typeof T.size = filepath => + new Promise((resolve, reject) => { + fs.stat(filepath, (err, stats) => { + if (err) { + reject(err); + } else { + resolve(stats.size); + } + }); + }); + +export const copyFile: typeof T.copyFile = (frompath, topath) => { + return new Promise((resolve, reject) => { + const readStream = fs.createReadStream(frompath); + const writeStream = fs.createWriteStream(topath); + + readStream.on('error', reject); + writeStream.on('error', reject); + + writeStream.on('open', () => readStream.pipe(writeStream)); + writeStream.once('close', () => resolve(true)); + }); +}; + +export const readFile: typeof T.readFile = ( + filepath: string, + encoding: 'utf8' | 'binary' | null = 'utf8', +) => { + if (encoding === 'binary') { + // `binary` is not actually a valid encoding, you pass `null` into node if + // you want a buffer + encoding = null; + } + // `any` as cannot refine return with two function overrides + // oxlint-disable-next-line typescript/no-explicit-any + return new Promise((resolve, reject) => { + fs.readFile(filepath, encoding, (err, data) => { + if (err) { + reject(err); + } else { + resolve(data); + } + }); + }); +}; + +export const writeFile: typeof T.writeFile = async (filepath, contents) => { + try { + await promiseRetry( + (retry, attempt) => { + return new Promise((resolve, reject) => { + fs.writeFile(filepath, contents, 'utf8', err => { + if (err) { + logger.error( + `Failed to write to ${filepath}. Attempted ${attempt} times. Something is locking the file - potentially a virus scanner or backup software.`, + ); + reject(err); + } else { + if (attempt > 1) { + logger.info( + `Successfully recovered from file lock. It took ${attempt} retries`, + ); + } + resolve(undefined); + } + }); + }).catch(retry); + }, + { + retries: 20, + minTimeout: 100, + maxTimeout: 500, + factor: 1.5, + }, + ); + + return undefined; + } catch (err) { + logger.error(`Unable to recover from file lock on file ${filepath}`); + throw err; + } +}; + +export const removeFile: typeof T.removeFile = filepath => { + return new Promise(function (resolve, reject) { + fs.unlink(filepath, err => { + return err ? reject(err) : resolve(undefined); + }); + }); +}; + +export const removeDir: typeof T.removeDir = dirpath => { + return new Promise(function (resolve, reject) { + fs.rmdir(dirpath, err => { + return err ? reject(err) : resolve(undefined); + }); + }); +}; + +export const removeDirRecursively: typeof T.removeDirRecursively = + async dirpath => { + if (await exists(dirpath)) { + for (const file of await listDir(dirpath)) { + const fullpath = join(dirpath, file); + if (fs.statSync(fullpath).isDirectory()) { + await removeDirRecursively(fullpath); + } else { + await removeFile(fullpath); + } + } + + await removeDir(dirpath); + } + }; + +export const getModifiedTime: typeof T.getModifiedTime = filepath => { + return new Promise(function (resolve, reject) { + fs.stat(filepath, (err, stats) => { + if (err) { + reject(err); + } else { + resolve(new Date(stats.mtime)); + } + }); + }); +}; diff --git a/packages/loot-core/src/platform/server/fs/index.electron.ts b/packages/loot-core/src/platform/server/fs/index.electron.ts index 185c309d02..4260ce7871 100644 --- a/packages/loot-core/src/platform/server/fs/index.electron.ts +++ b/packages/loot-core/src/platform/server/fs/index.electron.ts @@ -13,9 +13,6 @@ export { getDocumentDir, getBudgetDir, _setDocumentDir } from './shared'; let rootPath = path.join(__dirname, '..', '..', '..', '..'); switch (path.basename(__filename)) { - case 'bundle.api.js': // api bundle uses the electron bundle - account for its file structure - rootPath = path.join(__dirname, '..'); - break; case 'bundle.desktop.js': // electron app rootPath = path.join(__dirname, '..', '..'); break; diff --git a/packages/loot-core/src/server/main.ts b/packages/loot-core/src/server/main.ts index a7cf6bd3f4..201c37ac2f 100644 --- a/packages/loot-core/src/server/main.ts +++ b/packages/loot-core/src/server/main.ts @@ -1,7 +1,5 @@ // @ts-strict-ignore import './polyfills'; -import * as injectAPI from '@actual-app/api/injected'; - import * as asyncStorage from '../platform/server/asyncStorage'; import * as connection from '../platform/server/connection'; import * as fs from '../platform/server/fs'; @@ -126,8 +124,6 @@ handlers['app-focused'] = async function () { handlers = installAPI(handlers) as Handlers; -injectAPI.override((name, args) => runHandler(app.handlers[name], args)); - // A hack for now until we clean up everything app.handlers = handlers; app.combine( diff --git a/packages/loot-core/src/server/migrate/migrations.ts b/packages/loot-core/src/server/migrate/migrations.ts index b1daef7303..fdd6fc1671 100644 --- a/packages/loot-core/src/server/migrate/migrations.ts +++ b/packages/loot-core/src/server/migrate/migrations.ts @@ -147,15 +147,29 @@ function checkDatabaseValidity( appliedIds: number[], available: string[], ): void { - for (let i = 0; i < appliedIds.length; i++) { - if ( - i >= available.length || - appliedIds[i] !== getMigrationId(available[i]) - ) { - logger.error('Database is out of sync with migrations:', { + if (appliedIds.length > available.length) { + logger.error( + 'Database is out of sync with migrations (index past available):', + { appliedIds, available, - }); + }, + ); + throw new Error('out-of-sync-migrations'); + } + + for (let i = 0; i < appliedIds.length; i++) { + if (appliedIds[i] !== getMigrationId(available[i])) { + logger.error( + 'Database is out of sync with migrations (migration id mismatch):', + { + appliedIds, + available, + missing: available.filter( + m => !appliedIds.includes(getMigrationId(m)), + ), + }, + ); throw new Error('out-of-sync-migrations'); } } diff --git a/packages/loot-core/vite.api.config.ts b/packages/loot-core/vite.api.config.ts deleted file mode 100644 index 432c269a8d..0000000000 --- a/packages/loot-core/vite.api.config.ts +++ /dev/null @@ -1,58 +0,0 @@ -import path from 'path'; - -import { visualizer } from 'rollup-plugin-visualizer'; -import { defineConfig } from 'vite'; -import peggyLoader from 'vite-plugin-peggy-loader'; - -export default defineConfig(({ mode }) => { - const outDir = path.resolve(__dirname, '../api/app'); - const crdtDir = path.resolve(__dirname, '../crdt'); - - return { - mode, - ssr: { noExternal: true, external: ['better-sqlite3'] }, - build: { - target: 'node18', - outDir, - emptyOutDir: false, - ssr: true, - lib: { - entry: path.resolve(__dirname, 'src/server/main.ts'), - formats: ['cjs'], - }, - sourcemap: true, - rollupOptions: { - output: { - entryFileNames: 'bundle.api.js', - format: 'cjs', - name: 'api', - }, - }, - }, - resolve: { - extensions: [ - '.api.js', - '.api.ts', - '.api.tsx', - '.js', - '.ts', - '.tsx', - '.json', - ], - alias: [ - { - find: 'handlebars', - replacement: require.resolve('handlebars/dist/handlebars.js'), - }, - { - find: /^@actual-app\/crdt(\/.*)?$/, - replacement: path.resolve(crdtDir, 'src') + '$1', - }, - ], - }, - plugins: [ - peggyLoader(), - visualizer({ template: 'raw-data', filename: `${outDir}/stats.json` }), - ], - }; -}); diff --git a/upcoming-release-notes/6809.md b/upcoming-release-notes/6809.md new file mode 100644 index 0000000000..7746f5bac1 --- /dev/null +++ b/upcoming-release-notes/6809.md @@ -0,0 +1,6 @@ +--- +category: Maintenance +authors: [MatissJanis] +--- + +Remove cyclic dependency between API and loot-core diff --git a/yarn.lock b/yarn.lock index 0e250c40bb..f1d86cd79d 100644 --- a/yarn.lock +++ b/yarn.lock @@ -19,18 +19,22 @@ __metadata: languageName: node linkType: hard -"@actual-app/api@workspace:^, @actual-app/api@workspace:packages/api": +"@actual-app/api@workspace:packages/api": version: 0.0.0-use.local resolution: "@actual-app/api@workspace:packages/api" dependencies: "@actual-app/crdt": "workspace:^" better-sqlite3: "npm:^12.6.2" compare-versions: "npm:^6.1.1" + loot-core: "workspace:^" node-fetch: "npm:^3.3.2" - tsc-alias: "npm:^1.8.16" + rollup-plugin-visualizer: "npm:^6.0.5" typescript: "npm:^5.9.3" typescript-strict-plugin: "npm:^2.4.4" uuid: "npm:^13.0.0" + vite: "npm:^7.3.1" + vite-plugin-dts: "npm:^4.5.4" + vite-plugin-peggy-loader: "npm:^2.0.1" vitest: "npm:^4.0.18" languageName: unknown linkType: soft @@ -4879,6 +4883,60 @@ __metadata: languageName: node linkType: hard +"@microsoft/api-extractor-model@npm:7.33.1": + version: 7.33.1 + resolution: "@microsoft/api-extractor-model@npm:7.33.1" + dependencies: + "@microsoft/tsdoc": "npm:~0.16.0" + "@microsoft/tsdoc-config": "npm:~0.18.0" + "@rushstack/node-core-library": "npm:5.20.1" + checksum: 10/cb267ca0020a68b84570bc99e974d050acf8b17a47f1999998a9dbc2ef81453f8188a93970a6b2274890a5dd5015502b6cebe94da06d3583e65ca490dabf4c1e + languageName: node + linkType: hard + +"@microsoft/api-extractor@npm:^7.50.1": + version: 7.57.2 + resolution: "@microsoft/api-extractor@npm:7.57.2" + dependencies: + "@microsoft/api-extractor-model": "npm:7.33.1" + "@microsoft/tsdoc": "npm:~0.16.0" + "@microsoft/tsdoc-config": "npm:~0.18.0" + "@rushstack/node-core-library": "npm:5.20.1" + "@rushstack/rig-package": "npm:0.7.1" + "@rushstack/terminal": "npm:0.22.1" + "@rushstack/ts-command-line": "npm:5.3.1" + diff: "npm:~8.0.2" + lodash: "npm:~4.17.23" + minimatch: "npm:10.2.1" + resolve: "npm:~1.22.1" + semver: "npm:~7.5.4" + source-map: "npm:~0.6.1" + typescript: "npm:5.8.2" + bin: + api-extractor: bin/api-extractor + checksum: 10/7e6ff99a7ee07e34ae4e3d4e271ea794f20ba3b892932e94f3757f230b8f3d6a3f4c18c723c71d3bffdc7a5dd51c732201fc911089cdebae7a4a194d3e4de2e7 + languageName: node + linkType: hard + +"@microsoft/tsdoc-config@npm:~0.18.0": + version: 0.18.0 + resolution: "@microsoft/tsdoc-config@npm:0.18.0" + dependencies: + "@microsoft/tsdoc": "npm:0.16.0" + ajv: "npm:~8.12.0" + jju: "npm:~1.4.0" + resolve: "npm:~1.22.2" + checksum: 10/0470df5326181d876faba51617d011a632b2e3b420953e521bb865715d0db2fb0b8bfb3ccbcaef267356a1a7150d2ffba40022db5930db6b15fcb348bf846a4b + languageName: node + linkType: hard + +"@microsoft/tsdoc@npm:0.16.0, @microsoft/tsdoc@npm:~0.16.0": + version: 0.16.0 + resolution: "@microsoft/tsdoc@npm:0.16.0" + checksum: 10/1eaad3605234dc7e44898c15d1ba3c97fb968af1117025400cba572ce268da05afc36634d1fb9e779457af3ff7f13330aee07a962510a4d9c6612c13f71ee41e + languageName: node + linkType: hard + "@napi-rs/wasm-runtime@npm:^0.2.3": version: 0.2.12 resolution: "@napi-rs/wasm-runtime@npm:0.2.12" @@ -8016,7 +8074,7 @@ __metadata: languageName: node linkType: hard -"@rollup/pluginutils@npm:^5.0.1, @rollup/pluginutils@npm:^5.0.2": +"@rollup/pluginutils@npm:^5.0.1, @rollup/pluginutils@npm:^5.0.2, @rollup/pluginutils@npm:^5.1.4": version: 5.3.0 resolution: "@rollup/pluginutils@npm:5.3.0" dependencies: @@ -8197,6 +8255,77 @@ __metadata: languageName: node linkType: hard +"@rushstack/node-core-library@npm:5.20.1": + version: 5.20.1 + resolution: "@rushstack/node-core-library@npm:5.20.1" + dependencies: + ajv: "npm:~8.13.0" + ajv-draft-04: "npm:~1.0.0" + ajv-formats: "npm:~3.0.1" + fs-extra: "npm:~11.3.0" + import-lazy: "npm:~4.0.0" + jju: "npm:~1.4.0" + resolve: "npm:~1.22.1" + semver: "npm:~7.5.4" + peerDependencies: + "@types/node": "*" + peerDependenciesMeta: + "@types/node": + optional: true + checksum: 10/bd05a400fd96818a6382df7bc6a284adc78bbc8ae81c40760f2fee56a4124f0e56a38e007745bcf39c7449913e97f182860c1a344b56a31b8ba8445c21c6c012 + languageName: node + linkType: hard + +"@rushstack/problem-matcher@npm:0.2.1": + version: 0.2.1 + resolution: "@rushstack/problem-matcher@npm:0.2.1" + peerDependencies: + "@types/node": "*" + peerDependenciesMeta: + "@types/node": + optional: true + checksum: 10/62fda91629577a2f57de19be357cd0990da145ff4933f4d2cd48f423cc03b92fca06dd8916dcbaf1d307a201c104847c77066d45d79fd3c323c4949f0c99bf44 + languageName: node + linkType: hard + +"@rushstack/rig-package@npm:0.7.1": + version: 0.7.1 + resolution: "@rushstack/rig-package@npm:0.7.1" + dependencies: + resolve: "npm:~1.22.1" + strip-json-comments: "npm:~3.1.1" + checksum: 10/080a80e5c36b6861ee4a9a6e5ad9692cc3861cfb9edd0b02e9438aaaaa5a6e1b6f65275469d9f997696487841c7bb7daa69bba69c5e7301426056437bf544138 + languageName: node + linkType: hard + +"@rushstack/terminal@npm:0.22.1": + version: 0.22.1 + resolution: "@rushstack/terminal@npm:0.22.1" + dependencies: + "@rushstack/node-core-library": "npm:5.20.1" + "@rushstack/problem-matcher": "npm:0.2.1" + supports-color: "npm:~8.1.1" + peerDependencies: + "@types/node": "*" + peerDependenciesMeta: + "@types/node": + optional: true + checksum: 10/fe4da212e11c60b8a6a2de9cb7658b03c510831d365c560eedf26a20fa85c62a45f1865cff99c2b252dcd773329fcd2347dd89e5e2efd5694d7746f0a8aec172 + languageName: node + linkType: hard + +"@rushstack/ts-command-line@npm:5.3.1": + version: 5.3.1 + resolution: "@rushstack/ts-command-line@npm:5.3.1" + dependencies: + "@rushstack/terminal": "npm:0.22.1" + "@types/argparse": "npm:1.0.38" + argparse: "npm:~1.0.9" + string-argv: "npm:~0.3.1" + checksum: 10/51ca262eefbf07875f3e57fb402cba80e7ff36c14c0fc98c59af7be65407cafb4cbfe9b6738b549d91e687e40bb5720afb214efa1352a7a13c186241f92795f0 + languageName: node + linkType: hard + "@sideway/address@npm:^4.1.5": version: 4.1.5 resolution: "@sideway/address@npm:4.1.5" @@ -8900,6 +9029,13 @@ __metadata: languageName: node linkType: hard +"@types/argparse@npm:1.0.38": + version: 1.0.38 + resolution: "@types/argparse@npm:1.0.38" + checksum: 10/26ed7e3f1e3595efdb883a852f5205f971b798e4c28b7e30a32c5298eee596e8b45834ce831f014d250b9730819ab05acff5b31229666d3af4ba465b4697d0eb + languageName: node + linkType: hard + "@types/aria-query@npm:^5.0.1": version: 5.0.4 resolution: "@types/aria-query@npm:5.0.4" @@ -10519,6 +10655,94 @@ __metadata: languageName: node linkType: hard +"@volar/language-core@npm:2.4.28, @volar/language-core@npm:~2.4.11": + version: 2.4.28 + resolution: "@volar/language-core@npm:2.4.28" + dependencies: + "@volar/source-map": "npm:2.4.28" + checksum: 10/6c735027df0dfee142654e0aa9265111a82c21134366c08f4764743f74875ba8314fdc98865d37bf83ac7409dfea90b8538181a966681f3d01f68bbd999fef3a + languageName: node + linkType: hard + +"@volar/source-map@npm:2.4.28": + version: 2.4.28 + resolution: "@volar/source-map@npm:2.4.28" + checksum: 10/494b086be7ef6a46993941144a6961dcf9ecc4c830e2279031004496a7480727d6b0dc3f16776bf83aafe005084655c5664198f362a2c975d8267855de7b0a27 + languageName: node + linkType: hard + +"@volar/typescript@npm:^2.4.11": + version: 2.4.28 + resolution: "@volar/typescript@npm:2.4.28" + dependencies: + "@volar/language-core": "npm:2.4.28" + path-browserify: "npm:^1.0.1" + vscode-uri: "npm:^3.0.8" + checksum: 10/6176e1fccc3c060a6393ab33b9befb828542a813a72201f0a83a8e6607055ac98a838db32ce9f54fe305df51cd1fa0eefc30d5e16dd2391af0563c76746f6679 + languageName: node + linkType: hard + +"@vue/compiler-core@npm:3.5.28": + version: 3.5.28 + resolution: "@vue/compiler-core@npm:3.5.28" + dependencies: + "@babel/parser": "npm:^7.29.0" + "@vue/shared": "npm:3.5.28" + entities: "npm:^7.0.1" + estree-walker: "npm:^2.0.2" + source-map-js: "npm:^1.2.1" + checksum: 10/12af441c9ca51df2c0fb31f88b20966fc710c272818f65827dab44168f6d479b994d6f801d94511e78a7ddeced933c5b15e88f86b5528b155138a1938675a46f + languageName: node + linkType: hard + +"@vue/compiler-dom@npm:^3.5.0": + version: 3.5.28 + resolution: "@vue/compiler-dom@npm:3.5.28" + dependencies: + "@vue/compiler-core": "npm:3.5.28" + "@vue/shared": "npm:3.5.28" + checksum: 10/172ae6cf07dfdd94601981c27574a1329b25dded32a423627f7ecedd79492f5ad548305538f50e21900481f53881dff862a1c472ce5cc18ce38fad7c59bdc53a + languageName: node + linkType: hard + +"@vue/compiler-vue2@npm:^2.7.16": + version: 2.7.16 + resolution: "@vue/compiler-vue2@npm:2.7.16" + dependencies: + de-indent: "npm:^1.0.2" + he: "npm:^1.2.0" + checksum: 10/739ad06be19206b2715707c226a070509bcf28c31b539a6fc932d220eb7b0c09109d71fded573ed0c4073429793a3513ca4a4e69ad4f7afc0c5bc3c28639e871 + languageName: node + linkType: hard + +"@vue/language-core@npm:2.2.0": + version: 2.2.0 + resolution: "@vue/language-core@npm:2.2.0" + dependencies: + "@volar/language-core": "npm:~2.4.11" + "@vue/compiler-dom": "npm:^3.5.0" + "@vue/compiler-vue2": "npm:^2.7.16" + "@vue/shared": "npm:^3.5.0" + alien-signals: "npm:^0.4.9" + minimatch: "npm:^9.0.3" + muggle-string: "npm:^0.4.1" + path-browserify: "npm:^1.0.1" + peerDependencies: + typescript: "*" + peerDependenciesMeta: + typescript: + optional: true + checksum: 10/dc22d038509a58e5a5569fe19f67e7373067cde3531b1e405270dcbe026a8cdbb1de8a7a93d6aaa76a3c5b71393f5c6ec5d9125f0b050898cb96a5c62b4a8d88 + languageName: node + linkType: hard + +"@vue/shared@npm:3.5.28, @vue/shared@npm:^3.5.0": + version: 3.5.28 + resolution: "@vue/shared@npm:3.5.28" + checksum: 10/7d4132479462da5443b174d74052a00b796b57881e8e15298fad88acf4a9552db84ad8bb4104628d78bf7a57e43bfa985e65336abea6776b56277a1b95677a91 + languageName: node + linkType: hard + "@webassemblyjs/ast@npm:1.14.1, @webassemblyjs/ast@npm:^1.14.1": version: 1.14.1 resolution: "@webassemblyjs/ast@npm:1.14.1" @@ -10852,6 +11076,18 @@ __metadata: languageName: node linkType: hard +"ajv-draft-04@npm:~1.0.0": + version: 1.0.0 + resolution: "ajv-draft-04@npm:1.0.0" + peerDependencies: + ajv: ^8.5.0 + peerDependenciesMeta: + ajv: + optional: true + checksum: 10/3f11fa0e7f7359bef6608657f02ab78e9cc62b1fb7bdd860db0d00351b3863a1189c1a23b72466d2d82726cab4eb20725c76f5e7c134a89865e2bfd0e6828137 + languageName: node + linkType: hard + "ajv-formats@npm:^2.1.1": version: 2.1.1 resolution: "ajv-formats@npm:2.1.1" @@ -10866,6 +11102,20 @@ __metadata: languageName: node linkType: hard +"ajv-formats@npm:~3.0.1": + version: 3.0.1 + resolution: "ajv-formats@npm:3.0.1" + dependencies: + ajv: "npm:^8.0.0" + peerDependencies: + ajv: ^8.0.0 + peerDependenciesMeta: + ajv: + optional: true + checksum: 10/5679b9f9ced9d0213a202a37f3aa91efcffe59a6de1a6e3da5c873344d3c161820a1f11cc29899661fee36271fd2895dd3851b6461c902a752ad661d1c1e8722 + languageName: node + linkType: hard + "ajv-keywords@npm:^3.4.1, ajv-keywords@npm:^3.5.2": version: 3.5.2 resolution: "ajv-keywords@npm:3.5.2" @@ -10910,6 +11160,30 @@ __metadata: languageName: node linkType: hard +"ajv@npm:~8.12.0": + version: 8.12.0 + resolution: "ajv@npm:8.12.0" + dependencies: + fast-deep-equal: "npm:^3.1.1" + json-schema-traverse: "npm:^1.0.0" + require-from-string: "npm:^2.0.2" + uri-js: "npm:^4.2.2" + checksum: 10/b406f3b79b5756ac53bfe2c20852471b08e122bc1ee4cde08ae4d6a800574d9cd78d60c81c69c63ff81e4da7cd0b638fafbb2303ae580d49cf1600b9059efb85 + languageName: node + linkType: hard + +"ajv@npm:~8.13.0": + version: 8.13.0 + resolution: "ajv@npm:8.13.0" + dependencies: + fast-deep-equal: "npm:^3.1.3" + json-schema-traverse: "npm:^1.0.0" + require-from-string: "npm:^2.0.2" + uri-js: "npm:^4.4.1" + checksum: 10/4ada268c9a6e44be87fd295df0f0a91267a7bae8dbc8a67a2d5799c3cb459232839c99d18b035597bb6e3ffe88af6979f7daece854f590a81ebbbc2dfa80002c + languageName: node + linkType: hard + "algoliasearch-helper@npm:^3.26.0": version: 3.26.0 resolution: "algoliasearch-helper@npm:3.26.0" @@ -10943,6 +11217,13 @@ __metadata: languageName: node linkType: hard +"alien-signals@npm:^0.4.9": + version: 0.4.14 + resolution: "alien-signals@npm:0.4.14" + checksum: 10/306a7f4a88a982d1619ff313ed078bdfe52bb9d1381590ef4c1c245812ce7274b9b645a6233214e764a1adbef21863bdf74d10aa4fb30917456b7dd7779df5fc + languageName: node + linkType: hard + "ansi-align@npm:^3.0.1": version: 3.0.1 resolution: "ansi-align@npm:3.0.1" @@ -11101,7 +11382,7 @@ __metadata: languageName: node linkType: hard -"argparse@npm:^1.0.7": +"argparse@npm:^1.0.7, argparse@npm:~1.0.9": version: 1.0.10 resolution: "argparse@npm:1.0.10" dependencies: @@ -12881,7 +13162,7 @@ __metadata: languageName: node linkType: hard -"commander@npm:^9.0.0, commander@npm:^9.4.1": +"commander@npm:^9.4.1": version: 9.5.0 resolution: "commander@npm:9.5.0" checksum: 10/41c49b3d0f94a1fbeb0463c85b13f15aa15a9e0b4d5e10a49c0a1d58d4489b549d62262b052ae0aa6cfda53299bee487bfe337825df15e342114dde543f82906 @@ -14164,6 +14445,13 @@ __metadata: languageName: node linkType: hard +"de-indent@npm:^1.0.2": + version: 1.0.2 + resolution: "de-indent@npm:1.0.2" + checksum: 10/30bf43744dca005f9252dbb34ed95dcb3c30dfe52bfed84973b89c29eccff04e27769f222a34c61a93354acf47457785e9032e6184be390ed1d324fb9ab3f427 + languageName: node + linkType: hard + "debounce@npm:^1.2.1": version: 1.2.1 resolution: "debounce@npm:1.2.1" @@ -14500,6 +14788,13 @@ __metadata: languageName: node linkType: hard +"diff@npm:~8.0.2": + version: 8.0.3 + resolution: "diff@npm:8.0.3" + checksum: 10/52f957e1fa53db4616ff5f4811b92b22b97a160c12a2f86f22debd4181227b0f6751aa8fd711d6a8fcf4618acb13b86bc702e6d9d6d6ed82acfd00c9cb26ace2 + languageName: node + linkType: hard + "diffie-hellman@npm:^5.0.3": version: 5.0.3 resolution: "diffie-hellman@npm:5.0.3" @@ -15044,6 +15339,13 @@ __metadata: languageName: node linkType: hard +"entities@npm:^7.0.1": + version: 7.0.1 + resolution: "entities@npm:7.0.1" + checksum: 10/3c0c58d869c45148463e96d21dee2d1b801bd3fe4cf47aa470cd26dfe81d59e9e0a9be92ae083fa02fa441283c883a471486e94538dcfb8544428aa80a55271b + languageName: node + linkType: hard + "env-paths@npm:^2.2.0": version: 2.2.1 resolution: "env-paths@npm:2.2.1" @@ -16506,7 +16808,7 @@ __metadata: languageName: node linkType: hard -"fs-extra@npm:^11.1.1, fs-extra@npm:^11.2.0, fs-extra@npm:^11.3.3": +"fs-extra@npm:^11.1.1, fs-extra@npm:^11.2.0, fs-extra@npm:^11.3.3, fs-extra@npm:~11.3.0": version: 11.3.3 resolution: "fs-extra@npm:11.3.3" dependencies: @@ -16767,15 +17069,6 @@ __metadata: languageName: node linkType: hard -"get-tsconfig@npm:^4.10.0": - version: 4.11.0 - resolution: "get-tsconfig@npm:4.11.0" - dependencies: - resolve-pkg-maps: "npm:^1.0.0" - checksum: 10/f569a533ba6f68701e99a9af65c4b72186fc3446be7af9478906f047443d715a728959adae8661299ce49b5bb8edc06d942c81bce57632166104bce633600db8 - languageName: node - linkType: hard - "github-from-package@npm:0.0.0": version: 0.0.0 resolution: "github-from-package@npm:0.0.0" @@ -17016,7 +17309,7 @@ __metadata: languageName: node linkType: hard -"globby@npm:^11.0.4, globby@npm:^11.1.0": +"globby@npm:^11.1.0": version: 11.1.0 resolution: "globby@npm:11.1.0" dependencies: @@ -18028,7 +18321,7 @@ __metadata: languageName: node linkType: hard -"import-lazy@npm:^4.0.0": +"import-lazy@npm:^4.0.0, import-lazy@npm:~4.0.0": version: 4.0.0 resolution: "import-lazy@npm:4.0.0" checksum: 10/943309cc8eb01ada12700448c288b0384f77a1bc33c7e00fa4cb223c665f467a13ce9aaceb8d2e4cf586b07c1d2828040263dcc069873ce63cfc2ac6fd087971 @@ -18942,6 +19235,13 @@ __metadata: languageName: node linkType: hard +"jju@npm:~1.4.0": + version: 1.4.0 + resolution: "jju@npm:1.4.0" + checksum: 10/1067ff8ce02221faac5a842116ed0ec79a53312a111d0bf8342a80bd02c0a3fdf0b8449694a65947db0a3e8420e8b326dffb489c7dd5866efc380c0d1708a707 + languageName: node + linkType: hard + "joi@npm:^17.9.2": version: 17.13.3 resolution: "joi@npm:17.13.3" @@ -19456,7 +19756,7 @@ __metadata: languageName: node linkType: hard -"local-pkg@npm:^1.1.1": +"local-pkg@npm:^1.0.0, local-pkg@npm:^1.1.1": version: 1.1.2 resolution: "local-pkg@npm:1.1.2" dependencies: @@ -19590,7 +19890,7 @@ __metadata: languageName: node linkType: hard -"lodash@npm:^4.17.23": +"lodash@npm:^4.17.23, lodash@npm:~4.17.23": version: 4.17.23 resolution: "lodash@npm:4.17.23" checksum: 10/82504c88250f58da7a5a4289f57a4f759c44946c005dd232821c7688b5fcfbf4a6268f6a6cdde4b792c91edd2f3b5398c1d2a0998274432cff76def48735e233 @@ -19652,11 +19952,10 @@ __metadata: languageName: node linkType: hard -"loot-core@workspace:*, loot-core@workspace:packages/loot-core": +"loot-core@workspace:*, loot-core@workspace:^, loot-core@workspace:packages/loot-core": version: 0.0.0-use.local resolution: "loot-core@workspace:packages/loot-core" dependencies: - "@actual-app/api": "workspace:^" "@actual-app/crdt": "workspace:^" "@jlongster/sql.js": "npm:^1.6.7" "@reduxjs/toolkit": "npm:^2.11.2" @@ -19695,6 +19994,7 @@ __metadata: npm-run-all: "npm:^4.1.5" path-browserify: "npm:^1.0.1" peggy: "npm:5.0.6" + promise-retry: "npm:^2.0.1" rollup-plugin-visualizer: "npm:^6.0.5" slash: "npm:5.1.0" stream-browserify: "npm:^3.0.0" @@ -19812,7 +20112,7 @@ __metadata: languageName: node linkType: hard -"magic-string@npm:^0.30.0, magic-string@npm:^0.30.21, magic-string@npm:^0.30.3": +"magic-string@npm:^0.30.0, magic-string@npm:^0.30.17, magic-string@npm:^0.30.21, magic-string@npm:^0.30.3": version: 0.30.21 resolution: "magic-string@npm:0.30.21" dependencies: @@ -21001,6 +21301,15 @@ __metadata: languageName: node linkType: hard +"minimatch@npm:10.2.1, minimatch@npm:^10.1.2, minimatch@npm:^10.2.1": + version: 10.2.1 + resolution: "minimatch@npm:10.2.1" + dependencies: + brace-expansion: "npm:^5.0.2" + checksum: 10/d41c195ee1f2c70a75641088e36d0fa5fa286cb6fe48558e6d3bf3d95f640eda453c217707215389b12234df12175f65f338c0b841b36b0125177dbd6a80d026 + languageName: node + linkType: hard + "minimatch@npm:3.1.2, minimatch@npm:^3.0.2, minimatch@npm:^3.0.3, minimatch@npm:^3.0.4, minimatch@npm:^3.0.5, minimatch@npm:^3.1.1, minimatch@npm:^3.1.2": version: 3.1.2 resolution: "minimatch@npm:3.1.2" @@ -21019,15 +21328,6 @@ __metadata: languageName: node linkType: hard -"minimatch@npm:^10.1.2, minimatch@npm:^10.2.1": - version: 10.2.1 - resolution: "minimatch@npm:10.2.1" - dependencies: - brace-expansion: "npm:^5.0.2" - checksum: 10/d41c195ee1f2c70a75641088e36d0fa5fa286cb6fe48558e6d3bf3d95f640eda453c217707215389b12234df12175f65f338c0b841b36b0125177dbd6a80d026 - languageName: node - linkType: hard - "minimatch@npm:^5.0.1": version: 5.1.6 resolution: "minimatch@npm:5.1.6" @@ -21232,6 +21532,13 @@ __metadata: languageName: node linkType: hard +"muggle-string@npm:^0.4.1": + version: 0.4.1 + resolution: "muggle-string@npm:0.4.1" + checksum: 10/8fa2ea08f497c04069718bd3fd1909b382114dacbad832d10967ca72690de43f5f8492d8ccfbf827d6be63868ed5fc10395e7b7c082aa95997eea498586c6620 + languageName: node + linkType: hard + "multicast-dns@npm:^7.2.5": version: 7.2.5 resolution: "multicast-dns@npm:7.2.5" @@ -21251,13 +21558,6 @@ __metadata: languageName: node linkType: hard -"mylas@npm:^2.1.9": - version: 2.1.13 - resolution: "mylas@npm:2.1.13" - checksum: 10/37f335424463c422f48d50317aa0a34fe410fabb146cbf27b453a0aa743732b5626f56deaa190bca2ce29836f809d88759007976dc78d5d22b75918a00586577 - languageName: node - linkType: hard - "nano-spawn@npm:^2.0.0": version: 2.0.0 resolution: "nano-spawn@npm:2.0.0" @@ -22658,15 +22958,6 @@ __metadata: languageName: node linkType: hard -"plimit-lit@npm:^1.2.6": - version: 1.6.1 - resolution: "plimit-lit@npm:1.6.1" - dependencies: - queue-lit: "npm:^1.5.1" - checksum: 10/e4eaf018dc311fd4d452954c10992cd8a9eb72d168ec2274bb831d86558422703e1405a8978ffdd5c418654e6a25e10a0765a39bf3ce3a84dc799fe6268e0ea4 - languageName: node - linkType: hard - "plist@npm:3.1.0, plist@npm:^3.0.4, plist@npm:^3.0.5, plist@npm:^3.1.0": version: 3.1.0 resolution: "plist@npm:3.1.0" @@ -23864,13 +24155,6 @@ __metadata: languageName: node linkType: hard -"queue-lit@npm:^1.5.1": - version: 1.5.2 - resolution: "queue-lit@npm:1.5.2" - checksum: 10/8dd45c79bd25b33b0c7d587391eb0b4acc4deb797bf92fef62b2d8e7c03b64083f5304f09d52a18267d34d020cc67ccde97a88185b67590eeccb194938ff1f98 - languageName: node - linkType: hard - "queue-microtask@npm:^1.2.2": version: 1.2.3 resolution: "queue-microtask@npm:1.2.3" @@ -25169,13 +25453,6 @@ __metadata: languageName: node linkType: hard -"resolve-pkg-maps@npm:^1.0.0": - version: 1.0.0 - resolution: "resolve-pkg-maps@npm:1.0.0" - checksum: 10/0763150adf303040c304009231314d1e84c6e5ebfa2d82b7d94e96a6e82bacd1dcc0b58ae257315f3c8adb89a91d8d0f12928241cba2df1680fbe6f60bf99b0e - languageName: node - linkType: hard - "resolve@npm:^1.10.0, resolve@npm:^1.17.0, resolve@npm:^1.19.0, resolve@npm:^1.22.1, resolve@npm:^1.22.10": version: 1.22.10 resolution: "resolve@npm:1.22.10" @@ -25189,7 +25466,7 @@ __metadata: languageName: node linkType: hard -"resolve@npm:^1.22.8": +"resolve@npm:^1.22.8, resolve@npm:~1.22.1, resolve@npm:~1.22.2": version: 1.22.11 resolution: "resolve@npm:1.22.11" dependencies: @@ -25215,7 +25492,7 @@ __metadata: languageName: node linkType: hard -"resolve@patch:resolve@npm%3A^1.22.8#optional!builtin": +"resolve@patch:resolve@npm%3A^1.22.8#optional!builtin, resolve@patch:resolve@npm%3A~1.22.1#optional!builtin, resolve@patch:resolve@npm%3A~1.22.2#optional!builtin": version: 1.22.11 resolution: "resolve@patch:resolve@npm%3A1.22.11#optional!builtin::version=1.22.11&hash=c3c19d" dependencies: @@ -25754,6 +26031,17 @@ __metadata: languageName: node linkType: hard +"semver@npm:~7.5.4": + version: 7.5.4 + resolution: "semver@npm:7.5.4" + dependencies: + lru-cache: "npm:^6.0.0" + bin: + semver: bin/semver.js + checksum: 10/985dec0d372370229a262c737063860fabd4a1c730662c1ea3200a2f649117761a42184c96df62a0e885e76fbd5dace41087d6c1ac0351b13c0df5d6bcb1b5ac + languageName: node + linkType: hard + "send@npm:0.19.0": version: 0.19.0 resolution: "send@npm:0.19.0" @@ -26572,7 +26860,7 @@ __metadata: languageName: node linkType: hard -"string-argv@npm:^0.3.2": +"string-argv@npm:^0.3.2, string-argv@npm:~0.3.1": version: 0.3.2 resolution: "string-argv@npm:0.3.2" checksum: 10/f9d3addf887026b4b5f997a271149e93bf71efc8692e7dc0816e8807f960b18bcb9787b45beedf0f97ff459575ee389af3f189d8b649834cac602f2e857e75af @@ -26801,7 +27089,7 @@ __metadata: languageName: node linkType: hard -"strip-json-comments@npm:^3.1.1": +"strip-json-comments@npm:^3.1.1, strip-json-comments@npm:~3.1.1": version: 3.1.1 resolution: "strip-json-comments@npm:3.1.1" checksum: 10/492f73e27268f9b1c122733f28ecb0e7e8d8a531a6662efbd08e22cccb3f9475e90a1b82cab06a392f6afae6d2de636f977e231296400d0ec5304ba70f166443 @@ -26930,7 +27218,7 @@ __metadata: languageName: node linkType: hard -"supports-color@npm:^8.0.0": +"supports-color@npm:^8.0.0, supports-color@npm:~8.1.1": version: 8.1.1 resolution: "supports-color@npm:8.1.1" dependencies: @@ -27556,23 +27844,6 @@ __metadata: languageName: node linkType: hard -"tsc-alias@npm:^1.8.16": - version: 1.8.16 - resolution: "tsc-alias@npm:1.8.16" - dependencies: - chokidar: "npm:^3.5.3" - commander: "npm:^9.0.0" - get-tsconfig: "npm:^4.10.0" - globby: "npm:^11.0.4" - mylas: "npm:^2.1.9" - normalize-path: "npm:^3.0.0" - plimit-lit: "npm:^1.2.6" - bin: - tsc-alias: dist/bin/index.js - checksum: 10/a4c1988e645c0bbb993629f1cde79189549db35c2aeff7aa23bbf0864437f6dd15f91de3b51fe05cbd53e56ed32529710cc22855a8925c637357ab4c5e4f862a - languageName: node - linkType: hard - "tsconfck@npm:^3.0.3": version: 3.1.6 resolution: "tsconfck@npm:3.1.6" @@ -27764,6 +28035,16 @@ __metadata: languageName: node linkType: hard +"typescript@npm:5.8.2": + version: 5.8.2 + resolution: "typescript@npm:5.8.2" + bin: + tsc: bin/tsc + tsserver: bin/tsserver + checksum: 10/dbc2168a55d56771f4d581997be52bab5cbc09734fec976cfbaabd787e61fb4c6cf9125fd48c6f98054ce549c77ecedefc7f64252a830dd8e9c3381f61fbeb78 + languageName: node + linkType: hard + "typescript@npm:^5.0.4, typescript@npm:^5.9.3": version: 5.9.3 resolution: "typescript@npm:5.9.3" @@ -27774,6 +28055,16 @@ __metadata: languageName: node linkType: hard +"typescript@patch:typescript@npm%3A5.8.2#optional!builtin": + version: 5.8.2 + resolution: "typescript@patch:typescript@npm%3A5.8.2#optional!builtin::version=5.8.2&hash=5786d5" + bin: + tsc: bin/tsc + tsserver: bin/tsserver + checksum: 10/97920a082ffc57583b1cb6bc4faa502acc156358e03f54c7fc7fdf0b61c439a717f4c9070c449ee9ee683d4cfc3bb203127c2b9794b2950f66d9d307a4ff262c + languageName: node + linkType: hard + "typescript@patch:typescript@npm%3A^5.0.4#optional!builtin, typescript@patch:typescript@npm%3A^5.9.3#optional!builtin": version: 5.9.3 resolution: "typescript@patch:typescript@npm%3A5.9.3#optional!builtin::version=5.9.3&hash=5786d5" @@ -28113,7 +28404,7 @@ __metadata: languageName: node linkType: hard -"uri-js@npm:^4.2.2": +"uri-js@npm:^4.2.2, uri-js@npm:^4.4.1": version: 4.4.1 resolution: "uri-js@npm:4.4.1" dependencies: @@ -28443,6 +28734,29 @@ __metadata: languageName: node linkType: hard +"vite-plugin-dts@npm:^4.5.4": + version: 4.5.4 + resolution: "vite-plugin-dts@npm:4.5.4" + dependencies: + "@microsoft/api-extractor": "npm:^7.50.1" + "@rollup/pluginutils": "npm:^5.1.4" + "@volar/typescript": "npm:^2.4.11" + "@vue/language-core": "npm:2.2.0" + compare-versions: "npm:^6.1.1" + debug: "npm:^4.4.0" + kolorist: "npm:^1.8.0" + local-pkg: "npm:^1.0.0" + magic-string: "npm:^0.30.17" + peerDependencies: + typescript: "*" + vite: "*" + peerDependenciesMeta: + vite: + optional: true + checksum: 10/1504a8da02f8015c3138ef57a690179ad9b9d4369a054ae48b52a1c8cbc7ad05474551eab309cd90cf758800e17b67ccd13317aa5f8e28efde957547c7a339fb + languageName: node + linkType: hard + "vite-plugin-node-polyfills@npm:^0.25.0": version: 0.25.0 resolution: "vite-plugin-node-polyfills@npm:0.25.0" @@ -28671,6 +28985,13 @@ __metadata: languageName: node linkType: hard +"vscode-uri@npm:^3.0.8": + version: 3.1.0 + resolution: "vscode-uri@npm:3.1.0" + checksum: 10/80c2a2421f44b64008ef1f91dfa52a2d68105cbb4dcea197dbf5b00c65ccaccf218b615e93ec587f26fc3ba04796898f3631a9406e3b04cda970c3ca8eadf646 + languageName: node + linkType: hard + "vscode-uri@npm:~3.0.8": version: 3.0.8 resolution: "vscode-uri@npm:3.0.8"