mirror of
https://github.com/actualbudget/actual.git
synced 2026-05-06 20:15:33 -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>
44 lines
1.2 KiB
TypeScript
44 lines
1.2 KiB
TypeScript
import { afterEach, describe, expect, test } from 'vitest';
|
|
|
|
import * as api from '../index';
|
|
|
|
declare const __API_DATA_DIR__: string;
|
|
|
|
afterEach(async () => {
|
|
await api.shutdown();
|
|
});
|
|
|
|
describe('api CRUD roundtrip (Node)', () => {
|
|
test('creates a budget, writes, reads it back', async () => {
|
|
const internal = await api.init({ dataDir: __API_DATA_DIR__ });
|
|
|
|
await internal.send('create-budget', {
|
|
budgetName: 'Integration Test',
|
|
testMode: true,
|
|
testBudgetId: 'integration-test',
|
|
});
|
|
await api.loadBudget('integration-test');
|
|
|
|
const accountId = await api.createAccount(
|
|
{ name: 'Checking', offbudget: false },
|
|
0,
|
|
);
|
|
|
|
await api.addTransactions(accountId, [
|
|
{ date: '2026-04-01', amount: 1000, payee_name: 'Coffee' },
|
|
{ date: '2026-04-02', amount: -500, payee_name: 'Book' },
|
|
]);
|
|
|
|
const accounts = await api.getAccounts();
|
|
expect(accounts.map(a => a.name)).toContain('Checking');
|
|
|
|
const txns = await api.getTransactions(
|
|
accountId,
|
|
'2026-04-01',
|
|
'2026-04-30',
|
|
);
|
|
expect(txns).toHaveLength(2);
|
|
expect(txns.map(t => t.amount).sort((a, b) => a - b)).toEqual([-500, 1000]);
|
|
});
|
|
});
|