You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
fix(actions): reach global actions at their real registration key, and 404 an action that never dispatched (#3913) (#3930)
Object-less actions register under the literal 'global' (AppPlugin's
`action.object || 'global'`, ObjectQLPlugin.actionObjectKey) but the REST
fallback probed '*' — and engine.executeAction is an exact-string Map lookup
with no wildcard semantics, so that probe could only miss. /actions/global/:action
worked by accident (the path segment happened to spell the registration key);
/actions//:action never worked, and neither did falling back from an
object-scoped route to a global handler.
'global' is now canonical (GLOBAL_ACTION_OBJECT_KEY). One probe order —
[routed object, 'global', '*'] via actionHandlerObjectKeys — serves both the
REST route and the MCP run_action bridge, with the legacy '*' kept last so a
handler registered directly against it still resolves. A single-segment path
routes at 'global' instead of 400-ing.
The not-found exit also called deps.success(), so "no such action" went out as
HTTP 200 {success:true, data:{success:false, error}} and read as a success to
any caller that skipped the inner envelope. Nothing DISPATCHED there, so it is
a 404 now, joining the pre-dispatch answers this route already gives a status
(403 denied, 400 wrong action type, 503 unavailable), and it names the routed
object rather than whichever probe ran last.
A handler that RAN and rejected is unchanged: HTTP 200 with
{success:false, error, code?, fields?} — a business outcome, not a transport
error, per #3937. The line is "did a handler run".
client.actions.invoke/invokeGlobal still do not throw; the added catch is
load-bearing since client.fetch throws on every non-2xx.
0 commit comments