Skip to content

Retrofit async (promise) support to server extension-point callbacks #688

Description

@romain-pm

Follow-up from the architecture review of the feature/js-server-extensions branch (PR #687).

Context. Actions (.action.ts) accept async handlers: the engine settles returned promises through JSPromise.settle (GraalJS drains the microtask queue at the polyglot API boundary; unit-tested in JSPromiseTest). The three bridges written before that mechanism existed are still sync-only: registerNodeValidator, registerChoiceListInitializer, registerNodeLegacyAction (and registerRenderFilter), which is an inconsistent developer experience — an async callback silently misbehaves there instead of working or failing loudly.

Proposal. In each Java bridge (ChoiceListInitializerRegistrar, NodeValidatorRegistrar.collectViolations, NodeLegacyActionRegistrar.ActionBridge, RenderFilterRegistrar.RenderFilterBridge), pass the JS result through JSPromise.settle before converting it: microtask-resolvable promises (any async/await over synchronous work) then behave exactly like sync returns; never-settling promises produce an explicit error instead of a wrong result. Non-breaking — sync returns are untouched. Update the "no promises" wording in the TSDoc/guides accordingly.

Acceptance. Each of the four bridges has a unit test with an async callback fixture; guides no longer claim sync-only where async now works; existing Cypress specs stay green.

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