feat(server): align JSON-RPC dispatcher with openrpc.json (param shim + helpers) #50
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "development_mik"
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?
Closes hero_slides#49.
TL;DR
The
openrpc.jsonschema, generated client, and JS dashboard all use the new{collection, deck, slide}API shape; the dispatcher incrates/hero_slides_server/src/rpc.rswas still on the legacy{deck_path, slide_name, root_path}shape. 46 of 122 methods silently failed in the UI — the JS swallowed every error intry{…}catch{toast(…)}so the operator only ever saw side-effects (counter not incrementing, dropdown showing duplicate keys, slide editor not loading).This PR adds a single
legacy_param_shimthat runs beforematch req.method.as_str()and translates the public schema-shape params into the legacy keys handlers expect. Zero per-handler edits. Smoke harness drift went from 46 → 0 PARAM_MISMATCH.What's in here
1. Request preprocessor:
legacy_param_shim{collection, deck}deck_pathstate.registry.resolve_deck()with<root>/<deck>fallback for not-yet-existing decks (deck.delete / deck.rename){src_collection, src_deck}src_deck_path{dst_collection, dst_deck}dst_deck_path{collection}root_path+parent_pathstate.registry.lookup_root()(template.*, deck.create){slide}slide_name{slides}slide_names{to}to_position{filename}↔{file}{deck_path, folder, file}path<deck_path>/backgrounds/<folder>/<file>Already-present legacy keys are preserved (no overwrite). Resolver errors are silent so the handler returns its own clearer error if neither shape is provided.
2.
handle_deck_listshape fixdeck_name(matchesDeckSummaryschema) so the JS deck dropdown gets uniquely-keyed options. Pre-fix: every option was${col}::undefined, breaking deck switching + URL-hash auto-select.collectionfilter param the JS sends inloadDecks().3. Async helpers for direct use
param_deck_path(params, state, method)— async, returnsPathBuf. Use when a handler wants the resolver directly rather than going through the shim.param_collection_root(params, state, method)— async, returnsPathBuf.param_slide(params, method)— sync, mirrorsparam_string("slide", Some("slide_name"), method).4.
scripts/smoke_openrpc.pyPython stdlib only (zero deps). Reads
openrpc.json, calls every advertised method with minimal valid params over therpc.sock, and classifies the response:-32000 "Method not found".-32000 "Missing 'X' parameter"(schema drift class).Skips destructive methods by default;
--include-destructivere-registers the fixture between calls so prior mutations don't break later ones.Verification
Live against
http://127.0.0.1:9988/hero_slides/adminafter deploying this binary:Smoke harness:
The 15 remaining METHOD_MISSING are entirely undispatched features (
deckjobs.*,wizard.*,slide.setLink / clearLink / setImageModel / getStaleness / revertToLastGenerated / resolveContext,bg.extractTheme,deck.staleness,folder.pick) — separate scope; these need new handlers, not just shape fixes.Hero Browser MCP UI smoke (1440×900 headless, dark theme, console interceptor installed):
hero_slides_examples→ 2 deck cards render with state badges ✓hero_slides_intro→ all 6 slide thumbnails render with PNG previews ✓Editon a slide → editor loads with markdown content + preview pane + Save/Save & Quit/Save & Generate + image-model selector ✓console.messages = []at every stage ✓API smoke: all 5
collection.*,deck.list/get/getTheme/saveTheme/listThemes,slide.list/getContent/saveContent/setHidden/move/insert/delete/duplicate,template.list/get,bg.createFolderetc. — each manually round-tripped clean.Out of scope
400 "property 'image_config' is unsupported") but the local aibroker doesn't havegemini-3.1-flash-image-previewregistered (only Qwen / wan2.7 image models via Alibaba). Routing falls back to a Qwen model that doesn't accept Gemini'simage_config. Configuration gap, not code bug. Either register Gemini in aibroker'smodels.addor change the dashboard's defaultimage-model-basicmeta to a Qwen model. Will note on the issue close.Refs: