@openruntime/modern-plugin
v0.1.7
Published
`@openruntime/modern-plugin` lets a Modern.js app expose framework runtime state to OpenRuntime. It records information that Modern.js already knows: application render state, current route state, SSR state, hydration state, and optional business ready st
Readme
@openruntime/modern-plugin
@openruntime/modern-plugin lets a Modern.js app expose framework runtime
state to OpenRuntime. It records information that Modern.js already knows:
application render state, current route state, SSR state, hydration state, and
optional business ready state.
The plugin does not decide whether a business page is usable. Framework targets only describe framework lifecycle. Business readiness should use the business ready helpers described below.
Usage
Add the plugin in src/modern.runtime.ts:
import { openRuntimeModernPlugin } from "@openruntime/modern-plugin";
export default openRuntimeModernPlugin();Open the page with the CLI so it can connect every registered runtime, then query it:
pnpm exec openruntime open http://localhost:19081/
pnpm exec openruntime targets --url http://localhost:19081/
pnpm exec openruntime snapshot --url http://localhost:19081/
pnpm exec openruntime wait-for modern:route ready --url http://localhost:19081/ --where pathname=/ordersFor pages that expose multiple Runtime instances, including micro-frontend children, see Browser Connections and Multiple Runtimes.
For SSR state that must be sent before hydration, the plugin still accepts
bridge: { port: 17321 } as an optional server-side setting.
Targets
modern:app
Type: modern.app
This is the top-level Modern.js runtime signal for the current page. Use it as the quick "is the framework page currently healthy" check.
Statuses:
initializing: the plugin has been installed, but rendering has not started.rendering: Modern.js is rendering or route work is still in progress.ready: the current framework route is ready and no hydration error is active.error: a framework-level failure was observed. The snapshot data points to the failed target, usuallymodern:routeormodern:hydration.
Common snapshot data:
routeCount: number of known Modern.js routes.basename: router basename when Modern.js provides it.failedTargetId: failed target id when the app is inerror.failedStatus: failed target status, usuallyerror.reason: short reason such asroute-loader-error,route-component-error,route-error, or hydration fallback reason.pathname: current pathname when the failure is route-related.errorRouteIds: route ids that currently carry route errors.hydrationEventType: hydration event type when hydration failed.
modern:route
Type: modern.route
This is the single route target. It represents the current route state and keeps the route manifest on the target definition.
Statuses:
idle: no current route match has been observed yet.loading: navigation, loader, or redirect work is still in progress.ready: the current route match is stable and has no known route error.error: a route loader, route module, or router error was observed.
Target data from targets:
routes: route manifest for known routes.routes[].routeId: stable OpenRuntime route id. When a pathname is known, this is the pathname, such as/orders.routes[].path: Modern.js route path segment.routes[].pathname: resolved pathname when available.routes[].modernRouteId: original Modern.js route id.routes[].parentRouteId: parent route id for nested routes.routes[].index: whether this is an index route.routes[].hasLoader: whether the route has a real data loader.routes[].hasRouteComponent: whether the route declares a route component or lazy module.routes[].hasLazyModule: whether the route uses a lazy module.
Snapshot data from snapshot:
pathname: current browser pathname.navigation: current router navigation state.matches: current matched route chain only. Old route matches are not kept after navigation.matches[].loader: real data loader state when known:loading,success,redirect, orerror.matches[].routeComponent: shown only when the route component module failed; the value iserror.matches[].error: route-specific error details.errorRouteIds: route ids that currently have errors.
modern:route does not create separate loader or route component targets.
Loader and route component details stay inside the current matches array so a
snapshot describes the current route instead of a history of every visited
route.
Common waits:
pnpm exec openruntime wait-for modern:route ready --where pathname=/orders
pnpm exec openruntime wait-for modern:route error --where pathname=/brokenOptional Route Actions
The Modern.js plugin does not register route actions by default. Enable them explicitly when the page should expose route list and route navigation actions to Agents:
openRuntimeModernPlugin({
injectRouteListAction: true,
injectRouteNavigateAction: true,
});modern.route.list
Enabled by injectRouteListAction.
This safe action returns the same known route manifest stored on the
modern:route target.
pnpm exec openruntime run-action modern.route.listmodern.route.navigate
Enabled by injectRouteNavigateAction.
This state-changing action navigates through the Modern.js router. The to
input only accepts routes known by the current modern:route route manifest.
Use input options to read the current candidate route pathnames:
pnpm exec openruntime input-options --action modern.route.navigate --input to
pnpm exec openruntime run-action modern.route.navigate --payload '{"to":"/orders"}'
pnpm exec openruntime wait-for modern:route ready --where pathname=/ordersmodern:ssr
Type: modern.ssr
This target is registered only when SSR data exists or SSR work is observed. A
CSR-only page normally does not have modern:ssr.
Statuses:
unknown: SSR target was registered before detailed state was available.rendering: the server render has started and has not finished yet.server-rendered: server render completed and produced SSR payload.fallback: Modern.js fell back to client render.invalidated: browser hydration showed the SSR result could not be reused.error: SSR output is not usable because the server-rendered route failed.
Common snapshot data:
environment:serverorbrowser.runtimeId: OpenRuntime runtime id injected during SSR.renderId: render id injected during SSR.requestPathname: pathname for the SSR request when available.requestUrl: full SSR request URL when available.renderMode: Modern.js render mode, such asstringorstream.renderLevel: Modern.js hydration/render level when available.reason: fallback or invalidation reason when available.failedTargetId: failed target id when SSR becomeserror.failedStatus: failed target status.
Common wait:
pnpm exec openruntime wait-for modern:ssr server-rendered --where environment=servermodern:hydration
Type: modern.hydration
This target is registered only when Modern.js emits hydration events. A CSR-only
page normally does not have modern:hydration. If SSR failed before hydration,
the plugin suppresses this target so a failed SSR page is not shown as
hydration success.
Statuses:
running: client hydration has started.success: client hydration completed successfully.fallback: Modern.js downgraded to client render.error: hydration failed or emitted a recoverable hydration error.
Common snapshot data:
type: Modern.js hydration event type.renderLevel: Modern.js render level when available.renderMode: Modern.js render mode when available.reason: hydration fallback or recoverable-error reason.
When hydration enters error, modern:ssr becomes invalidated and
modern:app becomes error. Later hydration success events do not overwrite
the earlier hydration failure.
Garfish Targets
The package also exports Garfish helpers for Modern.js / EdenX host applications that use Garfish:
createOpenRuntimeGarfishReportercreateOpenRuntimeGarfishPlugincreateOpenRuntimeGarfishCustomLoader
Garfish is a singleton in the host page. Register the OpenRuntime Garfish
plugin in the host application before Garfish.run() or before the first
Garfish.loadApp():
import {
createOpenRuntimeGarfishCustomLoader,
createOpenRuntimeGarfishPlugin,
createOpenRuntimeGarfishReporter,
} from "@openruntime/modern-plugin";
const reporter = createOpenRuntimeGarfishReporter();
export const garfishOptions = {
plugins: [createOpenRuntimeGarfishPlugin({ reporter })],
customLoader: createOpenRuntimeGarfishCustomLoader({ reporter }),
};If the host already has a customLoader, pass it through loader so
OpenRuntime can wrap it instead of replacing it.
modern:garfish
Type: modern.garfish
Aggregate Garfish sub-application state for the current page.
modern:garfish:app:<name>
Type: modern.garfish.app
Per-sub-application state. The target records Garfish lifecycle state and
whether provider.render / provider.destroy was called through the
OpenRuntime custom loader.
Statuses:
idle: no Garfish app has been observed yet.registered: the app was registered.loading: Garfish started loading the app.loaded: Garfish loaded the app instance.evaluating: a sub-application script started executing.evaluated: a sub-application script executed.mounting: Garfish started mounting the app.rendering:provider.renderwas called through the OpenRuntime custom loader.mounted: Garfish mount completed.unmounting: Garfish started unmounting orprovider.destroywas called.unmounted: Garfish unmount completed.error: load, script execution, mount, or unmount failed.
Common waits:
pnpm exec openruntime wait-for modern:garfish:app:orders mounted
pnpm exec openruntime events --target-id modern:garfish:app:orders --limit 50Business Ready Target
The package also exports helpers for business-owned readiness:
registerOpenRuntimeReadymarkOpenRuntimeReadymarkOpenRuntimeReadyErrorunregisterOpenRuntimeReady
These helpers use target ids shaped as business:ready:<id> and type
business.ready.
Statuses:
pending: business target is registered but not ready yet.ready: business code marked the target as ready.error: business code marked the target as failed.
Business targets are owned by business code. If a route unmounts the business
component, the component should call unregisterOpenRuntimeReady so stale
business targets do not stay in later route snapshots.
Example:
import {
markOpenRuntimeReady,
registerOpenRuntimeReady,
unregisterOpenRuntimeReady,
} from "@openruntime/modern-plugin";
import { getOpenRuntimeFromWindow } from "@openruntime/core";
const runtime = getOpenRuntimeFromWindow();
if (runtime) {
registerOpenRuntimeReady({
runtime,
id: "checkout",
});
markOpenRuntimeReady(runtime, "checkout", {
screen: "checkout",
});
}
// When the owning page or component unmounts:
if (runtime) {
unregisterOpenRuntimeReady(runtime, "checkout");
}