hero_books_server: oschema-first migration + workspace de-freeze (issue #154) #158
No reviewers
Labels
No labels
prio_critical
prio_low
type_bug
type_contact
type_issue
type_lead
type_question
type_story
type_task
No milestone
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set.
Reference
lhumina_code/hero_books!158
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "development_mahmoud"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Migrates
hero_books_serverfrom the legacy OSIS /hero_rpcstack to theoschema-first
openrpc_server!stack, and de-freezes the whole workspace ontohero_lib
development(issue #154). Follows thehero_server_migration/herolib_openrpc/hero_admin_uiskills; same shape as the merged hero_browsermigration.
What changed
Backend → oschema (5 domains on one
rpc.sock,/api/{domain}/rpc):collections(12),books(books + libraries + search = 11),docs(9),memory(5),admin(2). Dotted/camelCase legacy names renamed to verbatimsnake_case (
collections.getPage→collections_get_page).server.health/rpc.discoverdrop to the runtime.src/api.rs=openrpc_server!overoschema/{domain};main→serve_domains_with(extra, …)whereextrais the preserved REST //img//pdf//mcp//adminrouter. The hand-rolled 3.4k-line dispatcher, acceptloop, and
/rpc+/healthhandlers are removed;rpc/*bridge the generatedtyped surface onto the existing handler logic.
Workspace de-freeze (now 100% on hero_lib
development):publishing::serverOSIS layer +hero_rpc_osisand the[patch."hero_rpc.git"]set;herolib_otoml→herolib_oschema.herolib_macros::openrpc_client!(multi-domain bundleHeroBooksClient), replacing legacyhero_rpc_derive; dropped the lasthero_blueprint[patch]and thehero_rpc_derive/hero_rpc2deps. No frozenhero_macros_previouspins remain.hero_proc_sdk/hero_lifecycleAPIs.Verification
cargo build --workspace+cargo clippy --workspace --examples --testsclean(0 warnings).
/api/domains.jsonlists all 5 domains;
books_list/library_list/collections_list/admin_logs_get/books_scan/books_get(error path) return correct typedshapes;
/health.json,/api/books/openrpc.jsonand the preserved REST/api/booksall serve.Admin UI
The hero_books admin pane (Books / Libraries / Collections) lands in
hero_components(development, separate change). The old Askamahero_books_adminis retired separately after parity sign-off.Not included (follow-ups)
hero_books_admin(gated on parity + sign-off).hero_books_examplesintegration harness to/api/{domain}/rpc+snake_case names;
lab infocheck.🤖 Generated with Claude Code
Switches the serving path from the hand-rolled JSON-RPC dispatcher to the macro-generated oschema surface. Each of the 5 domains (admin/books/collections/ docs/memory) is now served at /api/{domain}/rpc on hero_books/rpc.sock. - rpc_impls/{bridge,mod,collections,books,docs,memory,admin}.rs: thin trait impls. The bridge dispatches to the unchanged web::rpc handler logic by the legacy dotted method name and snake-cases the result keys into the typed Outputs (memory.* dynamic results returned as JSON strings; libraries.list unwrapped to the bare list). - web/axum_server.rs: build_extra_router (REST JSON API + /img + /pdf + /mcp + /admin) replaces the all-routes builder; start_rpc_only_server now hands that extra router + the 5 domain services to api::serve_domains_with. The macro owns the socket bind, /rpc + /openrpc.json + /health + /.well-known, banner and SIGTERM loop — so the hand-rolled accept loop, shutdown_signal, handler_rpc, handler_rpc_discover, handler_health and handler_well_known are deleted. - web/rpc.rs is kept as the handler/logic layer the bridge calls (the match dispatcher is no longer the entry point). Build + clippy clean. Runtime per-method result-shape verification + SDK regeneration (openrpc_client!) + dropping the last hero_blueprint patch are the next step (Phase 4).Completes the de-freeze: the SDK is now generated by herolib_macros::openrpc_client! from the server's oschema (verbatim snake_case wire names, multi-domain bundle), replacing the legacy hero_rpc_derive. With its last consumer migrated, the frozen hero_macros_previous mirrors are fully retired. - hero_books_sdk: openrpc_client!("../hero_books_server/oschema", service = "hero_books", name = "HeroBooksClient") → bundle client with .admin()/ .books()/.collections()/.docs()/.memory() domain accessors + per-domain typed Input/Output. Deps: herolib_macros/herolib_openrpc (was hero_rpc_derive/rpc2). - Drop the [patch."hero_blueprint.git"] set and the hero_rpc_derive/hero_rpc2 workspace deps; cargo update removes the frozen crates from the lockfile. The whole workspace now builds on hero_lib development — no frozen pins remain. - Delete the orphan openrpc.client.generated.rs (vestigial hero_rpc2 client). - Update examples to the bundle API (server.health → books.list liveness probe). - Fix a pre-existing clippy lint in hero_books_docusaurus tests. Build + clippy clean (workspace + examples + tests).The multi-domain oschema surface serves /api/{domain}/rpc, but the in-repo readers (hero_books_web's base.html rpc() helper, hero_books_app) still POST the legacy dotted methods (server.health, books.list, search.query, …) to bare /rpc. After the migration the server no longer answered /rpc, so those fetches got an empty 404 body and resp.json() threw 'Unexpected end of JSON input'. Re-add a /rpc compat route to the extra router that dispatches the dotted names through the unchanged handle_rpc_request dispatcher (the same logic the oschema bridge already calls). Both surfaces coexist — /api/{domain}/rpc (canonical) and /rpc (legacy alias) — with no route collision. The alias can be dropped once the web/app readers move to /api/{domain}/rpc. Verified on a live server: POST /rpc {server.health|books.list|rpc.discover} returns valid JSON; /api/books/rpc still works.The oschema migration removed the legacy OSIS `importservice.*` JSON-RPC methods, so the admin import page failed with '[-32601] Method not found: importservice.start'. Repoint loadNamespaces/submitImport to the REST endpoints (GET /api/namespaces, POST /api/import) — the same ones hero_books_web uses, proxied through the admin — matching the {namespaces:[{name,displayName}]} and {jobId} response shapes. Verified against a live server: /api/namespaces and /api/import return the expected shapes; the import job is created and pollable via /api/import/log/{id}.The admin router only forwarded /rpc to hero_books_server; /api/* was unrouted, so after the import page moved to REST (/api/import, /api/namespaces) those fetches hit a 404 with an empty body and resp.json() threw 'Unexpected end of JSON input'. Route /api/{*rest} to the existing api_proxy (same sub-router + AppState as /rpc). Verified end-to-end through admin.sock: GET /api/namespaces -> {namespaces:[...]}, POST /api/import -> {jobId}; /rpc still works.The import page only showed 'Import started' and never polled, so a slow or failed job looked like nothing happened. Add a progress panel that polls /api/import/log/{jobId} (the same endpoint hero_books_web uses), streams the log lines, shows a complete/failed/warnings status, and refreshes the library list on completion. Makes import outcomes (incl. errors like a missing hero_memory) visible instead of silent.View command line instructions
Checkout
From your project repository, check out a new branch and test the changes.Merge
Merge the changes and update on Forgejo.Warning: The "Autodetect manual merge" setting is not enabled for this repository, you will have to mark this pull request as manually merged afterwards.