import type { EngineMessageEvent, LynxEngineContext } from '../../types/index.js'; type EngineEventListener = (event: EngineMessageEvent) => void; /** * Main-thread-local implementation of the Engine context proxy * (`ContextProxy::Type::kEngine`). * * Buildless (vanilla) Lynx cards subscribe to engine lifecycle events instead * of exporting `globalThis.renderPage` / `globalThis.updatePage`: * * ```js * const engine = lynx.getEngine(); * engine.addEventListener('__RenderPage', onRenderPage); * engine.addEventListener('__DestroyLifetime', cleanup); * ``` * * The engine side (`LynxViewInstance`) must consult {@link hasEventListener} * before dispatching and fall back to the direct global call when no listener * is registered — this is what keeps existing ReactLynx bundles working. See * `TemplateAssembler::DispatchEventFromEngineToCoreContext` and * {@link dispatchEngineEventWithFallback}. * * Registration identity, invocation order, `once` and duplicate-add semantics * are delegated to `EventTarget`, exactly as `LynxCrossThreadContext` does for * `lynx.getJSContext()`, so the two contexts a card can reach behave alike. * Listeners receive an event whose `type` and `data` mirror the engine, where * `LepusClosureEventListener::ConvertEventToLepusValue` reads those same two * fields off the event before handing them to lepus. * * Unlike the JS context there is no RPC hop: the engine and the main-thread * script share a thread, so `dispatchEvent` delivers synchronously. */ export declare class LynxEngineContextImpl extends EventTarget implements LynxEngineContext { #private; addEventListener(type: string, listener: EngineEventListener, options?: boolean | AddEventListenerOptions): void; removeEventListener(type: string, listener: EngineEventListener, options?: boolean | EventListenerOptions): void; /** * Whether at least one listener is registered for `type`, regardless of its * capture flag. This is the web counterpart of * `ContextProxy::HasEventListener`, which the engine consults to choose * between the event channel and the legacy direct call. */ hasEventListener(type: string): boolean; /** * Dispatch an engine message event to the main-thread script. * * Accepts the `{ type, data }` shape used by `LynxCrossThreadContext` so card * code can dispatch onto the engine proxy with the same call shape it uses * for `lynx.getJSContext()`. Listeners run synchronously. */ dispatchEvent(event: EngineMessageEvent): number; /** * Stop delivering events. Called on teardown *after* `__DestroyLifetime` has * been delivered. * * Listeners are not individually unregistered. This proxy is owned by the * `LynxViewInstance` being destroyed — its only construction site — so once * that instance is unreachable the proxy and every listener it holds are * collected together. Clearing the ledger and refusing further dispatch is * the part callers can observe. */ dispose(): void; } /** * Deliver an engine lifecycle event to the main-thread script, mirroring * `TemplateAssembler::DispatchEventFromEngineToCoreContext`: * * - if the Engine context proxy has a listener for `eventName`, dispatch a * message event whose `data` carries the call arguments; * - otherwise fall back to calling the corresponding global function * (`globalThis.renderPage` / `globalThis.updatePage`) directly. * * The fallback is what keeps existing ReactLynx bundles — which export * `globalThis.renderPage` and never touch `lynx.getEngine()` — working * unchanged. * * `args` is passed as an array, matching the engine, which packs `args...` * into a `lepus::CArray`. Events dispatched outside this helper - such as * `__DestroyLifetime`, a bare teardown signal - carry no arguments and so do * not use the array shape. * * @returns `true` when the event channel was used, `false` when `directCall` * ran. Returned for observability (tests, tracing); callers may ignore it. */ export declare function dispatchEngineEventWithFallback(engineContext: LynxEngineContext, eventName: string, directCall: () => void, args: unknown[]): boolean; export {};