mirror of
https://github.com/actualbudget/actual.git
synced 2026-07-21 00:27:43 -05:00
* 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>
78 lines
2.0 KiB
JSON
78 lines
2.0 KiB
JSON
{
|
|
"name": "@actual-app/api",
|
|
"version": "26.6.0",
|
|
"description": "An API for Actual",
|
|
"license": "MIT",
|
|
"repository": {
|
|
"type": "git",
|
|
"url": "git+https://github.com/actualbudget/actual.git",
|
|
"directory": "packages/api"
|
|
},
|
|
"files": [
|
|
"@types",
|
|
"dist",
|
|
"!@types/**/*.test.d.ts",
|
|
"!@types/**/*.test.d.ts.map"
|
|
],
|
|
"main": "dist/index.js",
|
|
"types": "@types/index.d.ts",
|
|
"exports": {
|
|
".": {
|
|
"types": "./@types/index.d.ts",
|
|
"development": "./index.ts",
|
|
"browser": {
|
|
"types": "./@types/index.browser.d.ts",
|
|
"default": "./dist/browser.js"
|
|
},
|
|
"default": "./dist/index.js"
|
|
},
|
|
"./models": {
|
|
"types": "./@types/models.d.ts",
|
|
"development": "./models.ts",
|
|
"default": "./dist/models.js"
|
|
}
|
|
},
|
|
"publishConfig": {
|
|
"exports": {
|
|
".": {
|
|
"types": "./@types/index.d.ts",
|
|
"browser": {
|
|
"types": "./@types/index.browser.d.ts",
|
|
"default": "./dist/browser.js"
|
|
},
|
|
"default": "./dist/index.js"
|
|
},
|
|
"./models": {
|
|
"types": "./@types/models.d.ts",
|
|
"default": "./dist/models.js"
|
|
}
|
|
}
|
|
},
|
|
"scripts": {
|
|
"build": "vite build && tsgo --emitDeclarationOnly && vite build --config vite.browser.config.mts",
|
|
"test": "vitest --run",
|
|
"e2e": "playwright test",
|
|
"typecheck": "tsgo -b && tsc-strict"
|
|
},
|
|
"dependencies": {
|
|
"@actual-app/core": "workspace:*",
|
|
"@actual-app/crdt": "workspace:*",
|
|
"better-sqlite3": "^12.10.0",
|
|
"compare-versions": "^6.1.1",
|
|
"uuid": "^14.0.1"
|
|
},
|
|
"devDependencies": {
|
|
"@actual-app/vite-plugin-peggy": "workspace:*",
|
|
"@playwright/test": "1.59.1",
|
|
"@typescript/native-preview": "beta",
|
|
"rollup-plugin-visualizer": "^7.0.1",
|
|
"typescript-strict-plugin": "^2.4.4",
|
|
"vite": "^8.0.16",
|
|
"vite-plugin-node-polyfills": "patch:vite-plugin-node-polyfills@npm%3A0.28.0#~/.yarn/patches/vite-plugin-node-polyfills-npm-0.28.0-bac39616ee.patch",
|
|
"vitest": "^4.1.8"
|
|
},
|
|
"engines": {
|
|
"node": ">=20"
|
|
}
|
|
}
|