Decode the verified album cover response field and expose normalized cover details and last-upload timestamps through both album list actions. Preserve the legacy numeric timestamp shape, retain string timestamps for the native response, return null when no cover exists, and avoid additional network requests.
Document the new output contracts in the OneBot and MCP catalogs. Add independent wire fixtures and action-level regression tests for the protocol mapping and public response shapes.
Refs #257
Decode the folder modifier metadata returned by group file listings and project it as last upload time, uploader ID, and uploader name for both folder listing actions.
Regenerate the MCP catalog and add protocol, bridge, OneBot projection, and action schema coverage for the new fields.
Closes#248
Introduce packages/onebot/src/action-kit.ts — a zero-dependency,
type-inferring declarative layer for OneBot action params. Each action
declares its param contract (f.* coercers + optional cross-field rules)
and a `run` handler that receives typed, already-validated params.
Validation failures now return BAD_REQUEST naming the offending field
instead of falling through to ApiHandler's INTERNAL_ERROR catch.
- 141/142 actions migrated to defineAction/groupAction/groupUserAction
across info/message/friend/group-*/request/extended; only
.handle_quick_operation stays legacy (it needs the ApiHandler instance,
which run() does not receive).
- f.messageId() distinguishes signed/non-zero message ids from positive
group/user ids (f.uint()); int({min:0}).default(1800) fixes duration=0
(unmute), which the old `|| 1800` silently swallowed.
- run(p, ctx, raw) exposes the raw params as an escape hatch for the
irregular tail (alias-key fallbacks, arbitrary objects).
- action-docs.ts renders self-generated API docs from describe().
- ApiHandler dispatch / try-catch / response-wrapping unchanged (narrow seam).
Registered action name set is byte-identical before/after (142, verified
by runtime enumeration). Typecheck clean; onebot suite green (the
pre-existing websocket native-addon test failure is unrelated).