mirror of
https://github.com/logseq/logseq.git
synced 2026-05-18 18:02:35 +00:00
7.1 KiB
7.1 KiB
task--db-worker-nodejs-compatible
Goal
Make frontend.worker.db-worker and its dependencies run in both browser and Node.js. Add a Node.js daemon that can be started from the command line and exposes HTTP APIs to the same worker capabilities.
Scope
- Primary target:
src/main/frontend/worker/db_worker.cljs. - All dependencies used by db-worker:
src/main/frontend/worker/**,src/main/frontend/worker_common/**, and any browser-only utilities used by those namespaces. - Callers:
src/main/frontend/persist_db/browser.cljs,src/main/frontend/handler/worker.cljs, and any callers that assume a WebWorker or Comlink transport.
Refactor Items (Concrete Work List)
- Split worker core logic from runtime-specific host APIs.
- Create a core module (e.g.
frontend.worker.db-core) that contains thread-api functions and business logic. - Move all direct uses of
js/self,js/location,js/navigator,importScripts,BroadcastChannel, andnavigator.locksout of core.
- Create a core module (e.g.
- Add a platform adapter layer with a consistent interface for browser and Node.js.
- Define
frontend.worker.platforminterface: storage, kv-store, broadcast, websocket, crypto, timers, and env flags. - Implement
frontend.worker.platform.browserusing OPFS, IDB, BroadcastChannel, navigator.locks, WebSocket, andglobalThis. - Implement
frontend.worker.platform.nodeusingfs/promises,path,crypto, andws.
- Define
- Abstract sqlite storage and VFS specifics.
- Browser: keep OPFS SAH pool implementation.
- Node: use file-backed sqlite storage (via sqlite-wasm Node VFS or a Node sqlite binding).
- Route db path resolution through the platform adapter (data dir, per-repo paths).
- Replace
importScriptsbootstrap with an explicit init entrypoint.- Browser build still uses
:web-worker, but entrypoint should callinit!with a browser platform adapter. - Node build should call the same
init!with a Node adapter.
- Browser build still uses
- Normalize RPC and transport.
- Define a transport-agnostic RPC layer that accepts a method name and args (transit string or direct args).
- Keep Comlink for browser worker transport.
- Add HTTP transport for Node (see daemon section).
- Update shared-service for non-browser environments.
- Provide a "single-client" fallback for Node; no multi-client coordination is needed.
- Replace browser-only storage in RTC and crypto modules.
frontend.worker.rtc.cryptuses IDB/OPFS and should switch to the platform kv-store and file API.- Any other worker modules using
js/navigatoror OPFS should be routed through the platform adapter.
- Replace direct
js/WebSocketusage with a platform websocket factory.- Browser:
js/WebSocket. - Node:
wsclient with the same interface shape.
- Browser:
- Update caller-side initialization.
- Add a Node-specific db worker client (e.g.
frontend.persist-db.nodeorfrontend.persist-db.remote) that talks to the HTTP daemon. - Keep browser
frontend.persist-db.browserusing WebWorker + Comlink.
- Add a Node-specific db worker client (e.g.
- Build config changes.
- Add a Node build target in
shadow-cljs.ednfor db-worker (e.g.:db-worker-node). - Ensure shared code compiles for
:node-scriptor:node-librarywith the correct externs.
- Add a Node build target in
- Tests and fixtures.
- Add unit tests for platform adapters and storage abstraction.
- Add a minimal integration test that starts the Node daemon and exercises a small RPC call.
Refactor Steps (Milestones + Status)
Milestone 1: Architecture & Abstractions
- TODO 1. Inventory db-worker dependencies and classify browser-only APIs.
- TODO 2. Define a platform adapter interface (storage, kv, broadcast, websocket, crypto, timers, env flags).
- TODO 3. Extract db-worker core logic into a platform-agnostic module (e.g.
frontend.worker.db-core).
Milestone 2: Browser Path Parity
- TODO 4. Implement
frontend.worker.platform.browser. - TODO 5. Update db-worker entry to inject the platform adapter and call core init.
- TODO 6. Route OPFS/IDB usage through the platform adapter in worker submodules.
- TODO 7. Replace direct
js/WebSocketusage with platform websocket factory.
Milestone 3: Node Path & Daemon
- TODO 8. Implement
frontend.worker.platform.nodein single-client mode (no locks or BroadcastChannel). - TODO 9. Update shared-service to no-op/single-client behavior in Node.
- TODO 10. Add Node build target in
shadow-cljs.ednfor db-worker. - TODO 11. Implement Node daemon entrypoint and HTTP server.
- TODO 12. Add a Node client in frontend to call the daemon (HTTP + SSE/WS events).
Milestone 4: Validation
- TODO 13. Add tests: adapter unit tests + daemon integration smoke test.
- TODO 14. Verify browser worker path still works with Comlink.
Node.js Daemon Requirements
The db-worker should be runnable as a standalone process for Node.js environments.
Entry Point
- Provide a CLI entry (example:
bin/logseq-db-workerornode dist/db-worker-node.js). - CLI flags (suggested):
--host(default127.0.0.1)--port(default8080)--data-dir(path for sqlite files, required or default to~/.logseq/db-worker)--repo(optional: auto-open a repo on boot)--rtc-ws-url(optional)--log-level(defaultinfo)--auth-token(optional; bearer token for HTTP)
Lifecycle
- Initialize platform adapter (Node).
- Initialize sqlite module and storage roots.
- Start HTTP server.
- Emit readiness when init completes.
- Graceful shutdown on SIGINT/SIGTERM (close dbs, flush logs).
HTTP API (Minimum)
Use HTTP for RPC and event delivery. Prefer a single generic RPC entrypoint to avoid one endpoint per method.
Required endpoints:
GET /healthz->200 OKwhen process is alive.GET /readyz->200 OKonly after sqlite init completes.POST /v1/invoke- Request JSON:
method: string, e.g."thread-api/create-or-open-db"directPass: booleanargsTransit: string (transit-encoded args) ORargs: array for direct pass
- Response JSON:
ok: booleanresultTransit: string (transit-encoded result) whendirectPass=falseresult: any (whendirectPass=true)error: error object if failed
- Request JSON:
Event delivery options:
GET /v1/eventsusing SSE for worker -> client events- Event payload should mirror current
postMessagepayloads infrontend.handler.worker. - Each event should be tagged with
typeandpayload.
- Event payload should mirror current
- Alternatively, provide
WS /v1/eventswith the same payload format.
Security
- If
--auth-tokenis provided, requireAuthorization: Bearer <token>for all endpoints excepthealthzandreadyz. - Bind to localhost by default.
Notes on Compatibility Gaps
- OPFS and IndexedDB do not exist in Node; file-backed storage and a Node KV store are required.
BroadcastChannelandnavigator.locksare browser-only; Node should use a simpler single-client mode.Comlinkis browser-optimized; the Node daemon should use HTTP, not Comlink.
Success Criteria
- Browser build continues to work with WebWorker + Comlink.
- Node daemon can start from CLI, open a repo, and respond to at least:
list-dbcreate-or-open-dbqtransact
- A minimal client can call the daemon and receive event notifications.