mirror of
https://github.com/actualbudget/actual.git
synced 2026-05-05 22:52:20 -05:00
absurd-sql uses Atomics.wait for sync sqlite access, which only works
inside a Web Worker. Rather than forcing every consumer to wire up
their own worker + RPC glue, ship two artifacts:
- dist/browser.js: tiny main-thread facade (~10 KB). Reuses
packages/api/methods.ts verbatim by aliasing
@actual-app/core/server/main to browser/lib-stub.ts at build time;
every lib.send call posts to the worker.
- dist/worker.js: the full loot-core + sql.js + absurd-sql stack
(~3.6 MB) running in a Web Worker.
Consumer wiring:
const worker = new Worker(
new URL('@actual-app/api/dist/worker.js', import.meta.url),
{ type: 'module' },
);
await api.init({ worker, dataDir: '/documents', serverURL, password });
await api.getAccounts();
Same named imports as Node/Electron — the worker is the only
browser-specific wiring. Keeping the URL construction in consumer
code lets their bundler (Vite, Webpack, ...) handle worker.js as an
asset without forcing us onto a single bundler convention.
Tests split accordingly: Node runs the full CRUD roundtrip against
real loot-core; jsdom runs a facade test that verifies init
validation, postMessage payload shapes, and error propagation via
a mock Worker.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
32 lines
1.1 KiB
TypeScript
32 lines
1.1 KiB
TypeScript
import * as fsPromises from 'fs/promises';
|
|
import * as os from 'os';
|
|
import * as path from 'path';
|
|
|
|
import { vi } from 'vitest';
|
|
|
|
// 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<string, unknown>;
|
|
const lootCoreRoot = path.join(__dirname, '..', '..', 'loot-core');
|
|
return {
|
|
...actual,
|
|
migrationsPath: path.join(lootCoreRoot, 'migrations'),
|
|
bundledDatabasePath: path.join(lootCoreRoot, 'default-db.sqlite'),
|
|
demoBudgetPath: path.join(lootCoreRoot, 'demo-budget'),
|
|
};
|
|
},
|
|
);
|
|
|
|
global.IS_TESTING = true;
|
|
|
|
// Shared integration test lives in a filesystem-backed tmp dir.
|
|
const dataDir = path.join(
|
|
os.tmpdir(),
|
|
`api-it-${Date.now()}-${Math.random().toString(36).slice(2)}`,
|
|
);
|
|
await fsPromises.mkdir(dataDir, { recursive: true });
|
|
globalThis.__API_DATA_DIR__ = dataDir;
|