Skip to content

@object-ui/core has no default server dispatcher, so standalone consumers cannot run action.body at all #2904

Description

@os-zhuang

Split out of #2896, which is closed — the fix there was to stop mislabeling a server-side body ("No script provided for script action" → an error naming the real cause). This is the follow-up that #2896 explicitly deferred, filed so it is not buried in a closed issue.

Where things stand after #2895

ActionSchema.body (HookBodySchema — L1 expression / L2 sandboxed JS) is the spec's preferred binding for script actions. Bodies execute server-side, via POST /api/v1/actions/{object}/{action} → the runtime sandbox.

In the console this works: useConsoleActionRuntime registers a script handler, and registered handlers beat ActionRunner's built-ins.

handlers: { api: apiHandler, flow: flowHandler, script: serverActionHandler, modal: modalActionHandler },

Every other consumer of @object-ui/core — standalone renderers, SDUI hosts, embedded usage — registers no such handler, falls through to the built-in executeScript, and now gets a clear error telling them a body must run server-side. Clear, but still a dead end: there is no supported way to make it run without hand-rolling the dispatcher that app-shell already has.

Why it wasn't done in #2895

serverActionHandler needs three things core has no opinion about today:

  • authauthFetch, session/token plumbing;
  • base URLapp-shell reads VITE_SERVER_URL, a bundler-specific env convention core should not inherit;
  • object resolution — which object the action is scoped to (objApiName), plus the record-id resolution dance (_rowRecord, recordIdField, toolbar selection fallback).

Adding a default dispatcher means core acquires opinions on all three, or takes them as injected config. That is a design decision, not a patch.

Options worth weighing

  1. A factory in corecreateServerActionHandler({ fetch, baseUrl, resolveObject }) that consumers register themselves. Core stays opinion-free; the duplicated logic in useConsoleActionRuntime and RecordDetailView (which both hand-roll the same POST) collapses into one place.
  2. A registered-by-default handler wired from an existing provider (DataSourceProvider?) when one is present, so the common case needs no wiring.
  3. Leave it to consumers and treat the improved error message from fix(actions): one precedence for target/execute, and stop mislabeling server-side body #2895 as the whole answer — defensible if standalone body use is genuinely rare.

Option 1 looks strongest: it fixes the existing duplication between useConsoleActionRuntime and RecordDetailView regardless of whether standalone consumers ever adopt it, so it earns its keep either way.

Not in scope

Executing bodies client-side, in any form. L2 requires an isolated VM enforcing declared capabilities, timeoutMs and memoryMb — a browser has none, so client-side "enforcement" would be decoration. L1 is formula-engine (CEL) source, a different dialect from this package's ${…} ExpressionEvaluator, so interpreting it here would diverge silently. The client dispatches; it does not interpret. See #2896 for the full reasoning.

Refs #2895, #2896.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions