From 27164ec5ba9b6e7de1bbfe0e68b395b6a5b96495 Mon Sep 17 00:00:00 2001 From: byrongamatos Date: Fri, 10 Jul 2026 14:08:11 +0200 Subject: [PATCH] refactor(server): extract MetadataDB into lib/metadata_db.py (R3) Move-only. The library metadata cache -- the `MetadataDB` class (4,018 lines) plus the query helpers it owns (keyset paging cursors, the tuning grouping key, smart-arrangement naming, tag normalisation, the startup DB-restore swap) -- moves out of server.py into a flat `lib/` module. Every moved block is byte-identical to its server.py original; server.py is exactly origin/main minus the six cut ranges, minus the now-dead `import contextlib`, plus the import-back block and the constructor call site. server.py: 14,037 -> 9,705 lines. The one non-verbatim change is the seam that lets the class leave server.py: `MetadataDB.__init__` now takes `config_dir` explicitly instead of reading the module-level CONFIG_DIR, so `lib/metadata_db.py` does no IO at import (Principle V). The `meta_db` singleton stays in server.py, so `server.meta_db` (282 refs) and `server.app` (67 refs) resolve unchanged and no route moves. None of the 114 `monkeypatch.setattr(server, ...)` targets moved. Logging still goes through the `feedBack.server` logger, so log filters and caplog assertions resolve to the same logger object. `tests/test_settings_export_library_db.py` imports `_apply_pending_db_restore` from metadata_db (the test moves with its subject); no other test changed. Verified: pyflakes clean on the new module (zero undefined names, zero unused imports) and no new undefined name in server.py; pytest 2341 passed; node --test 1030 passed; eslint 0 errors; uvicorn boot smoke serves /api/version, /api/library, and all three migrated plugins' src/ module graphs (stems, studio, editor -> 200). Co-Authored-By: Claude Opus 4.8 (1M context) --- CHANGELOG.md | 17 + docs/size-exemptions.md | 7 +- lib/metadata_db.py | 4373 ++++++++++++++++++++ lib/scan_worker.py | 2 +- server.py | 4728 +--------------------- tests/test_settings_api.py | 2 +- tests/test_settings_export_library_db.py | 13 +- 7 files changed, 4604 insertions(+), 4538 deletions(-) create mode 100644 lib/metadata_db.py diff --git a/CHANGELOG.md b/CHANGELOG.md index e71f5511..324c2850 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,23 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] +### Changed +- **`MetadataDB` moved out of `server.py` into `lib/metadata_db.py` (R3, move-only).** + The library metadata cache — the `MetadataDB` class (4,018 lines) plus the query + helpers it owns (keyset paging cursors, the tuning grouping key, smart-arrangement + naming, tag normalisation, the startup DB-restore swap) — now lives in its own flat + `lib/` module. `server.py` drops from **14,037 → 9,705 lines** and keeps the + `meta_db` singleton, so `server.meta_db` and `server.app` resolve exactly as before + and every route is untouched. The only non-verbatim change is the seam that lets the + class leave `server.py`: `MetadataDB.__init__` now takes `config_dir` explicitly + (`meta_db = MetadataDB(CONFIG_DIR)`) instead of reading the module-level `CONFIG_DIR`, + which also means `lib/metadata_db.py` performs no IO at import (Principle V). Logging + still goes through the `feedBack.server` logger, so existing log filters and `caplog` + assertions resolve to the same logger object. `tests/test_settings_export_library_db.py` + now imports `_apply_pending_db_restore` from `metadata_db` (the test moved with its + subject); no other test changed. Every moved block is byte-identical to its + `server.py` original. + ### Added - **Plugins can ship an ES-module `src/` tree (module-migration rails, R0).** The host gains three things so a plugin can move off a single global-scope `screen.js` IIFE onto native ES modules with **no build step**: (1) a new sandboxed `GET /api/plugins/{id}/src/{path}` route that serves a plugin's `src/` source subtree, containment-checked by the same `safe_join` guard as `assets/` (traversal/absolute/NUL → 404); (2) the live-edit cache contract — `Cache-Control: no-cache` + a weak mtime/size `ETag` + `If-None-Match`→`304` — applied to `src/`, `screen.js`, and `assets/` (previously `screen.js` sent no cache headers and `assets/` emitted an ETag but never revalidated), so an edited module reloads on refresh while unchanged ones `304`; and (3) `scriptType`/`minHost` passthrough from `plugin.json` to `/api/plugins`, with the loader injecting a plugin that declares `"scriptType":"module"` as `