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
JavaScript modules can now implement the server-side extension points that previously required a Java OSGi module — choicelist initializers, server-side validators, actions (both .do-bound and client-callable), render filters, and content patches — plus a third-party SDK so other bundles can consume them. Delivered across two reviewable PRs: #687 (extension points, actions, SDK) and #697 (content patches). Design decisions are recorded as ADRs 0001–0008 in docs/adr/.
Follow-up (stays open after #687 merges):#690 — actions endpoint v2 (dedicated servlet transport, non-breaking).
Explicitly out of scope of this epic's delivery: Rules/Listeners in JS (the registrar mechanism makes this a one-subclass addition whenever prioritized — see the POC's moduleGlobalObject mapper in npm-modules-engine#125) and UI extensions.
Developer experience
Every capability is a single typed function from @jahia/javascript-modules-library, called once at module init — no XML, no OSGi component boilerplate, no separate Java module. Each accepts idiomatic JS/TS signatures with the underlying Java objects still reachable as an escape hatch, and each supports async callbacks (microtask-based — the server runtime has no timers or async I/O).
Choicelist initializer — populates a Content Editor dropdown, referenced from CND as choicelist[key]:
Server-side validator — rejects invalid saves with a field-level or node-level error in Content Editor and GraphQL:
registerNodeValidator({nodeType: "mymodule:article"},(node)=>{constemail=node.getPropertyAsString("email");if(email&&!email.includes("@")){return{message: "Please provide a valid email address",propertyName: "email"};}});
Legacy node action — an HTTP endpoint bound to a content node (<nodeUrl>.<name>.do), for Java-module parity and existing .do integrations:
Actions — server functions callable from a client island as a plain typed await, with optional input validation via any Standard Schema-compatible library:
// rates.action.ts — compiled once for the server, once into a client fetch stubexportconstgetExchangeRate=action(z.object({currency: z.string()}),({ currency })=>lookupRate(currency));
Content patch — versioned, run-once content transformation, tracked by core's patch status store so it runs exactly once per environment.
Third-party SDK — for other OSGi bundles that need to consume JS-declared extensions without a polyglot dependency (org.jahia.modules.javascript.modules.engine.sdk, the only package the engine bundle exports).
Full guides: docs/2-guides/4-legacy-node-actions, docs/2-guides/5-choicelist-initializers, docs/2-guides/6-content-patches, docs/2-guides/7-actions, docs/3-reference/3-node-validators.
Original epic description (imported from Jira)
Minimum scope :
Choicelist initializers
Actions
Optionnal:
Filters (cached only ?)
UI extensions
Nice to have:
Rules / Listeners in JS
Migration script
Imported from Jira, on Thu Jan 30, 2025
Issue: BACKLOG-21005 in project: DX BACKLOG
Priority: Unspecified Type: Epic
Reporter: @romain-pm (Romain Gauthier)
Assignee: @Fgerthoffert (team-goat)
Created: Mon May 15, 2023, last updated: Fri Jan 17, 2025
Status: Open
JavaScript modules can now implement the server-side extension points that previously required a Java OSGi module — choicelist initializers, server-side validators, actions (both
.do-bound and client-callable), render filters, and content patches — plus a third-party SDK so other bundles can consume them. Delivered across two reviewable PRs: #687 (extension points, actions, SDK) and #697 (content patches). Design decisions are recorded as ADRs 0001–0008 indocs/adr/.What shipped
org.jahia.bin.Actionparity)Follow-up (stays open after #687 merges): #690 — actions endpoint v2 (dedicated servlet transport, non-breaking).
Explicitly out of scope of this epic's delivery: Rules/Listeners in JS (the registrar mechanism makes this a one-subclass addition whenever prioritized — see the POC's
moduleGlobalObjectmapper in npm-modules-engine#125) and UI extensions.Developer experience
Every capability is a single typed function from
@jahia/javascript-modules-library, called once at module init — no XML, no OSGi component boilerplate, no separate Java module. Each accepts idiomatic JS/TS signatures with the underlying Java objects still reachable as an escape hatch, and each supportsasynccallbacks (microtask-based — the server runtime has no timers or async I/O).Choicelist initializer — populates a Content Editor dropdown, referenced from CND as
choicelist[key]:Server-side validator — rejects invalid saves with a field-level or node-level error in Content Editor and GraphQL:
Legacy node action — an HTTP endpoint bound to a content node (
<nodeUrl>.<name>.do), for Java-module parity and existing.dointegrations:Actions — server functions callable from a client island as a plain typed
await, with optional input validation via any Standard Schema-compatible library:Render filter — participates in the render chain like a Java
AbstractFilter:Content patch — versioned, run-once content transformation, tracked by core's patch status store so it runs exactly once per environment.
Third-party SDK — for other OSGi bundles that need to consume JS-declared extensions without a polyglot dependency (
org.jahia.modules.javascript.modules.engine.sdk, the only package the engine bundle exports).Full guides:
docs/2-guides/4-legacy-node-actions,docs/2-guides/5-choicelist-initializers,docs/2-guides/6-content-patches,docs/2-guides/7-actions,docs/3-reference/3-node-validators.Original epic description (imported from Jira)
Minimum scope :
Optionnal:
Nice to have: