API reference
Exports of @sigx/runtime-core v0.13.0.
All examples assume a named import from the package root:
import { component, defineApp } from '@sigx/runtime-core';
The package also exposes ./jsx-runtime and ./jsx-dev-runtime subpaths (both aliasing the main build) for TSX transpilation via jsxImportSource, a separate ./internals entry for renderer authors, and an ./inspect entry with the inspection-only topic registry for tooling (see Inspection).
Component system
component
Define a component from a setup function that returns a render (view) function. setup runs once; the returned function is the reactive render. Setup may be sync or async — async setup is awaited during SSR and errors on the client (SIGX102).
function component<
TCombined extends Record<string, any> = {},
TRef = ExtractExposed<TCombined>,
TSlots = ExtractSlots<TCombined>
>(
setup: (ctx: ComponentSetupContext<PlatformElement, StripInternalMarkers<TCombined>, TCombined, TRef, TSlots>) => ViewFn | Promise<ViewFn>,
options?: ComponentOptions
): ComponentFactory<TCombined, TRef, TSlots>;
setup— the setup function receiving aComponentSetupContext; returns aViewFn(or a promise of one).options— optionalComponentOptions(currently{ name? }).- Returns a
ComponentFactoryusable as a JSX element.
getCurrentInstance
Return the setup context of the currently executing component, or null outside setup. Used to build composables.
function getCurrentInstance(): ComponentSetupContext<any, any, any> | null;
- Returns the active
ComponentSetupContext, ornullif called outside a component's setup.
getComponentMeta
Return the registered metadata (name and setup) for a component factory. Used by DevTools.
function getComponentMeta(factory: Function): { name?: string; setup: SetupFn<any, any, any, any> } | undefined;
factory— a component factory.- Returns
{ name?, setup }, orundefinedif the factory is not registered.
isComponent
Type guard that returns true for SignalX components (functions carrying a __setup property), and false for plain function components or strings.
function isComponent(type: unknown): type is ComponentLike;
type— the value to test.- Returns
trueif it is a SignalX component factory.
compound
Create a compound component by attaching sub-components as static properties. Enables the Parent.Child pattern (e.g. Menu.Item, Card.Body) while preserving full TypeScript inference for both the parent and its children.
function compound<
TMain extends AnyComponentFactory,
TSub extends Record<string, AnyComponentFactory>
>(main: TMain, sub: TSub): TMain & TSub;
main— the main/parent component factory.sub— an object whose values are the sub-components to attach.- Returns the main component with the sub-components attached as static properties.
Lifecycle hooks
Each hook must be called synchronously during setup. Called outside a component they warn and no-op (no throw).
onMounted
Register a callback to run after the component mounts. Receives a MountContext with the root element.
function onMounted(fn: (ctx: MountContext) => void): void;
fn— callback invoked post-mount with{ el }.
onUnmounted
Register a cleanup callback to run when the component unmounts. The place to clear timers and unsubscribe.
function onUnmounted(fn: (ctx: MountContext) => void): void;
fn— cleanup callback invoked on unmount with{ el }.
onCreated
Register a callback that runs immediately after setup completes, before the first render.
function onCreated(fn: () => void): void;
fn— callback invoked once after setup, before first render.
onUpdated
Register a callback that runs after every reactive re-render of the component.
function onUpdated(fn: () => void): void;
fn— callback invoked after each re-render.
Application
defineApp
Create a renderer-agnostic application instance with a chainable use / hook / directive / defineProvide / mount / unmount API.
function defineApp<TContainer = any>(rootComponent: JSXElement): App<TContainer>;
rootComponent— the root JSX element to render.- Returns an
App<TContainer>instance.
JSX runtime
jsx
The core JSX factory called by TSX transpilation. Builds VNodes, resolves components, and processes model bindings.
function jsx(type: string | Function | typeof Fragment, props: JSXProps | null, key?: string): JSXElement;
type— an intrinsic tag, component factory, orFragment.props— element props, ornull.key— optional reconciliation key.- Returns a
JSXElement. The fast path skips props cloning unless amodel/model:*prop is present.
jsxs
JSX factory variant for elements with multiple children; delegates to jsx.
function jsxs(type: string | typeof Fragment | Function, props?: Record<string, unknown>, key?: string): JSXElement;
type— an intrinsic tag, component factory, orFragment.props— element props.key— optional reconciliation key.- Returns a
JSXElement.
jsxDEV
Dev-mode JSX factory; an alias of jsx.
const jsxDEV: typeof jsx;
Fragment
VNode type marker for fragments — grouping children without a wrapper element.
const Fragment: unique symbol; // Symbol.for('sigx.Fragment')
Text
VNode type marker for text nodes.
const Text: unique symbol; // Symbol.for('sigx.Text')
Comment
VNode type marker for comment / placeholder nodes. Falsy children become Comment placeholders so positional diffing does not shift sibling indices when conditionals toggle.
const Comment: unique symbol; // Symbol.for('sigx.Comment')
Lazy loading & async
lazy
Wrap a dynamic-import loader into a lazy component loaded on first render. Adds preload() and isLoaded(). While the chunk loads the wrapper renders null; wrap it in <Defer> for a fallback. A load rejection throws from render (routes to the nearest errorScope, then app.onError).
function lazy<T extends AnyComponentFactory>(loader: ComponentLoader<T>): LazyComponentFactory<T>;
loader— a function returning a dynamic import of the component.- Returns a
LazyComponentFactory<T>(the component pluspreload/isLoaded/__lazy).
Defer
Boundary component that shows a fallback while lazy chunks beneath it load (a pending useData read renders through its own component's match(), not a wrapper). On SSR the fallback streams with the shell and one replacement arrives when everything pending below it — chunks and keyed data — resolves.
const Defer: ComponentFactory<DeferProps, void, { default?: () => JSXElement | JSXElement[] | null }>;
- Accepts a
fallbackprop (a node or a function returning a node) and a default slot.
isLazyComponent
Type guard for lazy-loaded components (checks the __lazy marker).
function isLazyComponent(component: any): component is LazyComponentFactory<any>;
component— the value to test.- Returns
trueif it is a lazy component factory.
useData
The keyed async read. Auto-runs its fetcher and returns a reactive AsyncState<T>; the render re-runs as the state changes. Every read has a key — the reactive trigger, the cache / SSR identity, and the fetcher's input. A static string key is SSR-transferable: it runs during SSR, serializes its value under the key into window.__SIGX_ASYNC__, restores on hydration without refetching, and dedupes per key. A getter key may return a string or a tuple (serialized to canonical JSON); a falsy result holds the read in idle.
// Static key: runs on the server, serialized under `key`, restored on hydration.
function useData<T>(
key: string,
fetcher: (arg: string, ctx: AsyncFetcherContext) => Promise<T>,
opts?: AsyncOptions
): AsyncState<T>;
// Reactive key: string or tuple; a falsy result skips the fetch (state 'idle').
function useData<T, const K extends KeyValue>(
key: () => K | Falsy,
fetcher: (arg: K, ctx: AsyncFetcherContext) => Promise<T>,
opts?: AsyncOptions
): AsyncState<T>;
key— a static string, or a getter returning a string / tuple / falsy. A static tuple is rejected (parameters that change belong in a getter).fetcher— an async function producing the value; receives the resolved key and a context whosesignalis anAbortSignal. Runs untracked.opts.server— run the fetcher during SSR. Defaulttrue;server: falserenders the pending arm on the server and fetches after hydration (still keyed).- Returns an
AsyncState<T>— see AsyncState.
useAction
The async write. The manual counterpart to useData: never auto-runs, triggered by .run(input). run never rejects — it resolves a settled RunResult<T>. In-flight runs are never aborted; a newer run() or reset() supersedes the observation (the older run resolves { ok: false, error: SupersededError } and never writes state).
function useAction<T, In = void>(
fn: (input: In, ctx: AsyncFetcherContext) => Promise<T>,
opts?: ActionOptions
): AsyncAction<T, In>;
fn— the write; receives theruninput and a context whosesignalis anAbortSignal.- Returns an
AsyncAction<T, In>withstate(idle | pending | ready | errored),value,error,loading(state === 'pending'),match(),run(input): Promise<RunResult<T>>, andreset().
all
Combine several AsyncStates into one all-or-nothing state (one match for a whole view). A pure derived view — no fetching. Object form gives named value/errors records; the rest-tuple form gives positional ones.
function all<S extends Record<string, AsyncState<unknown>>>(sources: S): AllState<ValuesOf<S>, ErrorsOf<S>>;
function all<S extends readonly AsyncState<unknown>[]>(...sources: S): AllState<ValuesOf<S>, ErrorsOf<S>>;
Derived state: any member idle ⇒ idle; else any errored ⇒ errored; else any pending ⇒ pending; else any refreshing ⇒ refreshing; else ready. AllState<T, E> extends AsyncState<T> with errors: E (collect-all; .error stays first-error-wins).
useStream
Composable for progressive text (LLM-token-style). Accumulates a streamed AsyncIterable<string> into a reactive string; SSR-aware via the key (streams on the server, restores on hydration without re-running the source, live on client navigation).
function useStream(
key: string,
source: () => AsyncIterable<string>
): { readonly value: string };
key— the serialization/restore key.source— a function returning an async iterable of text chunks.- Returns a
{ value }string signal that grows as chunks arrive.
Models & two-way binding
registerModelProcessor
Register an extension model processor for intrinsic-element model handling. Extension processors run before the platform processor (DOM/Lynx/Terminal), in registration order, and the first one returning true wins — so packs and apps can add model behavior for custom elements or widget libraries without replacing the platform's. Registering the same function twice is a no-op.
function registerModelProcessor(fn: ModelProcessor): void;
fn— aModelProcessor:(type, props, modelBinding, originalProps) => boolean. Returntrueto claim the binding (skip the fallback),falseto defer to later processors.
setPlatformModelProcessor is the separate, platform-identity seam used by renderer packages and is unchanged — registerModelProcessor is the additive extension tier.
createModel
Create a two-way binding Model<T> from a [sourceObject, key] tuple and an update handler.
function createModel<T>(tuple: [object, string], updateHandler: (value: T) => void): Model<T>;
tuple— a[sourceObject, key]pair identifying the bound value.updateHandler— called with the new value on write.- Returns a
Model<T>.
createModelFromBinding
Create a Model<T> from a full binding tuple [obj, key, handler] for forwarding scenarios.
function createModelFromBinding<T>(binding: ModelBindingTuple<T>): Model<T>;
binding— a[obj, key, handler]tuple.- Returns a
Model<T>.
isModel
Type guard that detects Model<T> objects via the sigx.model symbol. Used by the JSX runtime.
function isModel(value: unknown): value is Model<unknown>;
value— the value to test.- Returns
trueif it is aModel.
Error handling
errorScope
Setup-time error boundary for the calling component's own subtree — a function, not a wrapper component. Catches setup / render / reactive-re-render throws beneath it and data errors bubbled by a match() with no error arm. Does not catch fetcher rejections (those are values on .error) or DOM event-handler throws (those go to app.onError). retry is a real remount.
function errorScope(options: ErrorScopeOptions): void;
interface ErrorScopeOptions {
fallback?: (error: Error, retry: () => void) => JSXElement;
onError?: (error: Error, instance: ComponentInstance | null, info: string) => void;
}
fallback— rendered in place of the subtree while errored; omitted ⇒ renders nothing (the scope still stops propagation).onError— observer called before the fallback renders; its own throws are swallowed.
SupersededError
Error a superseded useAction run resolves with ({ ok: false, error: SupersededError }); never written to .error.
class SupersededError extends Error {
readonly name = 'SupersededError';
}
SigxError
Base error class for all runtime errors; carries a stable code (SIGX###) and an optional suggestion.
class SigxError extends Error {
readonly code: string;
readonly suggestion?: string;
declare readonly cause?: Error;
constructor(message: string, options: { code: string; suggestion?: string; cause?: Error });
}
code— the stable error code.suggestion— optional remediation hint.cause— optional underlying error.
SigxErrorCode
Frozen map of error code constants grouped by category (app / render / DI).
const SigxErrorCode: {
readonly NO_MOUNT_FUNCTION: 'SIGX001';
readonly RENDER_TARGET_NOT_FOUND: 'SIGX100';
readonly MOUNT_TARGET_NOT_FOUND: 'SIGX101';
readonly ASYNC_SETUP_CLIENT: 'SIGX102';
readonly PROVIDE_OUTSIDE_SETUP: 'SIGX200';
readonly PROVIDE_INVALID_INJECTABLE: 'SIGX201';
};
noMountFunctionError
Construct the SIGX001 error — no mount function provided and no platform default.
function noMountFunctionError(): SigxError;
- Returns the
SIGX001SigxError.
renderTargetNotFoundError
Construct the SIGX100 error — render target selector not found.
function renderTargetNotFoundError(selector: string): SigxError;
selector— the selector that could not be resolved.- Returns the
SIGX100SigxError.
mountTargetNotFoundError
Construct the SIGX101 error — mount target selector not found.
function mountTargetNotFoundError(selector: string): SigxError;
selector— the selector that could not be resolved.- Returns the
SIGX101SigxError.
asyncSetupClientError
Construct the SIGX102 error — async setup attempted on the client (only supported during SSR).
function asyncSetupClientError(componentName: string): SigxError;
componentName— the offending component's name.- Returns the
SIGX102SigxError.
provideOutsideSetupError
Construct the SIGX200 error — defineProvide called outside component setup.
function provideOutsideSetupError(): SigxError;
- Returns the
SIGX200SigxError.
provideInvalidInjectableError
Construct the SIGX201 error — defineProvide called with a non-injectable.
function provideInvalidInjectableError(): SigxError;
- Returns the
SIGX201SigxError.
Dependency injection
defineInjectable
Define an injectable service or value. The returned callable token resolves the nearest provided instance up the component tree, or lazily creates a global singleton if none was provided.
function defineInjectable<T>(factory: () => T): InjectableFunction<T>;
factory— produces the value when an instance must be created.- Returns an
InjectableFunction<T>(callable token).
defineProvide
Provide a new injectable instance at the current component level, visible to descendants. Must run during setup; otherwise throws SIGX200 / SIGX201.
function defineProvide<T>(useFn: InjectableFunction<T>, factory?: () => T): T;
useFn— the injectable token to provide.factory— optional override factory for the provided instance.- Returns the provided instance.
useAppContext
Return the current AppContext from the component tree (provided at root during mount / hydrate / SSR), or null.
function useAppContext(): AppContext | null;
- Returns the active
AppContext, ornull.
defineFactory
Create a factory with managed subscriptions, disposal, and a real instance lifetime. Parameterless factories become injectables; parameterized ones return FactoryFunction creators (still usable with defineProvide).
function defineFactory<R>(
setup: (ctx: SetupFactoryContext, ...args: unknown[]) => R,
lifetime: Lifetime,
typeIdentifier?: guid
): InjectableFunction<R & { dispose: () => void }>;
function defineFactory<R, T1>(setup: (ctx: SetupFactoryContext, p1: T1) => R, lifetime: Lifetime, id?: guid): FactoryFunction<[T1], R & { dispose: () => void }>;
// ...overloads up to 5 parameters
setup— receives aSetupFactoryContextand any creator arguments. Must return an object or function (primitives throw).lifetime— aLifetimestring literal; honored since core0.5.0:'singleton'— one instance perAppContext, created on first resolution and disposed onapp.unmount(). Outside any app context, one instance per JS realm.'scoped'— the nearest instance provided viadefineProvidein the component tree; falls back to the app-context instance when no provider exists.'transient'— a new instance per call, auto-disposed with the calling component (or manually viadispose()).
typeIdentifier— optionalguididentity.- Returns an
InjectableFunction(parameterless) or aFactoryFunctioncreator (parameterized).
dispose is attached as a non-enumerable property (a setup-returned dispose is delegated to) and is idempotent. Parameterized non-transient factories honor arguments at first creation only — later calls resolve the existing shared instance.
SubscriptionHandler
Collects unsubscribe callbacks and disposes them together. Used by defineFactory contexts.
class SubscriptionHandler {
add(unsub: () => void): void;
unsubscribe(): void;
}
add(unsub)— register an unsubscribe callback.unsubscribe()— run and clear all registered callbacks.
Directives
defineDirective
Identity function that marks a directive definition (with the sigx.directive symbol) for the use:name prop syntax.
function defineDirective<T = any, El = any>(definition: DirectiveDefinition<T, El>): DirectiveDefinition<T, El>;
definition— the directive's lifecycle hooks (created/mounted/updated/unmounted).- Returns the same definition, branded.
isDirective
Type guard for directive definitions created by defineDirective.
function isDirective(value: any): value is DirectiveDefinition;
value— the value to test.- Returns
trueif it is a directive definition.
Messaging
createTopic
Create an in-memory pub/sub Topic<T>. subscribe() auto-unsubscribes via onUnmounted when called inside a component.
function createTopic<T>(options?: CreateTopicOptions): Topic<T>;
interface CreateTopicOptions {
/** Tooling metadata; topics WITH a namespace register in the inspection registry. */
namespace?: string;
/** Tooling metadata. */
name?: string;
/** Called when subscriberCount transitions 0 → 1 (refCount pattern). */
onActivate?(): void;
/** Called when subscriberCount transitions back to 0 (last unsubscribe or destroy). */
onDeactivate?(): void;
}
options— metadata plus refCount lifecycle hooks.- Returns a
Topic<T>.
Behavior contract (Topic v2):
publishisolates subscriber errors — a throwing handler is logged viaconsole.errorand neither skips later subscribers nor propagates into the publisher. Publishing to a destroyed topic is a no-op.subscribethrows on a destroyed topic — a handler attached afterdestroy()could never be cleaned up, so it is rejected loudly instead of leaking.onActivate/onDeactivatefire on the 0 → 1 and → 0 subscriber transitions, letting producers pay for work only while observed (e.g.@sigx/storeruns its per-key state watchers only while the key's event has subscribers). Hook errors are isolated.- Topics created with a
namespaceregister in the inspection registry (see Inspection);destroy()unregisters.
createTopicGroup
Create a typed group of topics keyed by an event map — mitt-level DX on the Topic primitive. Topics are created lazily per key on first access and are namespaced/registered like any other topic.
function createTopicGroup<EventMap extends Record<string, any>>(options?: { namespace?: string }): {
topics: { [K in keyof EventMap]: Topic<EventMap[K]> };
destroy(): void;
};
options— optional{ namespace? }applied to every created topic.- Returns
{ topics, destroy };destroy()destroys all created topics. Accessing a key on a destroyed group throws.
const group = createTopicGroup<{ loggedIn: User; loggedOut: void }>({ namespace: 'auth#1.events' });
group.topics.loggedIn.publish(user); // payload type-checked
group.topics.loggedIn.subscribe(u => {}); // u: User
group.destroy();
toSubscriber
Wrap a Topic as a subscribe-only view, hiding publish and destroy.
function toSubscriber<T>(topic: Topic<T>): { subscribe: (handler: (data: T) => void) => Subscription };
topic— the topic to wrap.- Returns an object exposing only
subscribe.
Inspection (@sigx/runtime-core/inspect)
A separate ./inspect package entry exposing the inspection-only topic registry for tooling (devtools, diagnostics). The DX contract: typed application code holds Topic<T> references; strings are tooling metadata. The registry is deliberately Topic<unknown>-typed and realm-global — do not use it as an app-level lookup mechanism; share typed topic references instead. Only topics created with a namespace register; destroy() unregisters.
import { getTopic, listTopics, subscribeTopics, onTopicCreated } from '@sigx/runtime-core/inspect';
Patterns use * wildcards matched over ${namespace}.${name} (e.g. 'todos#1.*', '*.actions.*').
getTopic
function getTopic(namespace: string, name: string): Topic<unknown> | undefined;
Look up a live registered topic by exact namespace and name.
listTopics
function listTopics(pattern?: string): Topic<unknown>[];
List live registered topics, optionally filtered by a *-wildcard pattern.
subscribeTopics
function subscribeTopics(
pattern: string,
handler: (data: unknown, meta: { namespace: string; name: string }) => void
): Subscription;
Subscribe to every registered topic matching a pattern — both topics that already exist and topics created later. One Subscription tears everything down. Auto-unsubscribes on component unmount when called inside a setup.
onTopicCreated
function onTopicCreated(handler: (topic: Topic<unknown>) => void): Subscription;
Register a handler for every topic that registers from now on. Handler errors are isolated. Auto-unsubscribes on component unmount when called inside a setup.
Utilities
signal
Re-export of signal() from @sigx/reactivity for convenience. The ComponentSetupContext also exposes it as ctx.signal.
export { signal } from '@sigx/reactivity';
Utils
Static utility helpers; currently exposes isPromise.
class Utils {
static isPromise(value: any): boolean;
}
isPromise(value)— thenable detection; returnstruefor promise-like values.
guid
Generate a v4-style GUID string. guid is also a string type alias of the same name (both exported from models/index).
const guid: () => string;
type guid = string;
- Returns a new GUID string.
Lifetimes
Lifetime
Lifetime options for defineFactory (and consumers like @sigx/store's defineStore). A string-literal union; the lifetime is enforced (see defineFactory for the semantics of each value).
type Lifetime = 'singleton' | 'scoped' | 'transient';
Internal
__registerComponentPlugin
Internal HMR hook (registerComponentPlugin re-exported under a __-prefixed name). Not part of the stable public API — listed for completeness only.
function __registerComponentPlugin(plugin: ComponentPlugin): void;
plugin— aComponentPluginwith an optionalonDefinehook.
Types
Define (namespace)
The preferred, discoverable API for typing component props, events, models, slots, and expose. Combine members with the & intersection.
namespace Define {
type Prop<TName extends string, TType, Required extends boolean = false> =
Required extends false ? { [K in TName]?: TType } : { [K in TName]: TType };
type Event<TName extends string, TDetail = void> = { [K in TName]?: EventDefinition<TDetail> };
type Model<TNameOrType, TType = void> = /* default: model + update:modelValue; named: model:name + update:name */;
type Slot<TName extends string, TProps = void> = {
__slots?: { [K in TName]: TProps extends void
? () => JSXElement | JSXElement[] | null
: (props: TProps) => JSXElement | JSXElement[] | null };
};
type Expose<T> = { __exposed?: { __type: T } };
}
ComponentSetupContext
The context object passed to a component's setup function. renderFn / update() are HMR escape hatches.
interface ComponentSetupContext<TElement = PlatformElement, TProps extends Record<string, any> = {}, TEvents extends Record<string, any> = {}, TRef = any, TSlots = {}> extends SetupContext {
el: TElement;
signal: typeof signal;
props: PropsAccessor<TProps>;
slots: SlotsObject<TSlots>;
emit: EmitFn<TEvents>;
parent: ComponentSetupContext | null;
onMounted(fn: (ctx: MountContext<TElement>) => void): void;
onUnmounted(fn: (ctx: MountContext<TElement>) => void): void;
onCreated(fn: () => void): void;
onUpdated(fn: () => void): void;
expose(exposed: TRef): void;
renderFn: ViewFn | null;
update(): void;
}
ComponentFactory
Return type of component(). Callable as JSX, plus internal __-branded props used by the renderer.
type ComponentFactory<TCombined extends Record<string, any>, TRef, TSlots> =
((props: StripForJSX<Omit<TCombined, EventNames<TCombined>>>
& EventHandlers<TCombined>
& SlotProps<TSlots>
& SyncProps<TCombined>
& ExternalModelProps<TCombined>
& JSX.IntrinsicAttributes
& ComponentAttributeExtensions
& { ref?: Ref<TRef>; children?: any }) => JSXElement)
& { __setup: SetupFn<any, any, any, any>; __name?: string; __islandId?: string; __props: any; __events: any; __ref: TRef; __slots: TSlots };
AnyComponentFactory
Structural constraint accepting any ComponentFactory (used by lazy / compound) without contravariance issues.
type AnyComponentFactory = {
(...args: any[]): any;
__setup: SetupFn<any, any, any, any>;
__props: any;
__events: any;
__ref: any;
__slots: any;
};
Model
Two-way binding object: .value reads/writes, .binding forwards.
interface Model<T> {
value: T;
readonly binding: ModelBindingTuple<T>;
readonly [MODEL_SYMBOL]: true;
}
// ModelBindingTuple<T> = readonly [object, string, (value: T) => void]
App
Chainable app instance returned by defineApp(). The _-prefixed members are @internal for renderers.
interface App<TContainer = any> {
config: AppConfig;
use<Options>(plugin: Plugin<Options> | PluginInstallFn<Options>, options?: Options): App<TContainer>;
defineProvide<T>(useFn: InjectableFunction<T>, factory?: () => T): T;
hook(hooks: AppLifecycleHooks): App<TContainer>;
directive(name: string, definition: DirectiveDefinition): App<TContainer>;
directive(name: string): DirectiveDefinition | undefined;
mount(container: TContainer, mountFn?: MountFn<TContainer>): App<TContainer>;
unmount(): void;
_context: AppContext;
_isMounted: boolean;
_container: TContainer | null;
_rootComponent: JSXElement;
}
App / plugin type cluster
The supporting types for the app and plugin system (from app-types.ts).
interface AppConfig {
onError?(err: Error, instance: ComponentInstance | null, info: string): boolean | void; // usually set via app.onError(fn)
warnHandler?(...args: any[]): void;
performance?: boolean;
}
interface AppLifecycleHooks {
onComponentCreated?(instance: ComponentInstance): void;
onComponentMounted?(instance: ComponentInstance): void;
onComponentUnmounted?(instance: ComponentInstance): void;
onComponentUpdated?(instance: ComponentInstance): void;
onComponentError?(err: unknown, instance: ComponentInstance, info: string): boolean | void;
}
interface AppContext {
app: App;
provides: Map<symbol, unknown>;
config: AppConfig;
hooks: AppLifecycleHooks[];
directives: Map<string, DirectiveDefinition>;
}
interface Plugin<Options = any> { name?: string; install(app: App, options?: Options): void; }
type PluginInstallFn<Options = any> = (app: App, options?: Options) => void;
type MountFn<TContainer = any> = (element: JSXElement, container: TContainer, appContext: AppContext) => (() => void) | void;
type UnmountFn<TContainer = any> = (container: TContainer) => void;
interface ComponentInstance { name?: string; ctx: ComponentSetupContext; vnode: VNode; }
VNode / JSXElement / JSXChild / JSXChildren
Core virtual-node and JSX value types.
type VNode = {
type: string | typeof Fragment | typeof Text | typeof Comment | Function;
props: Record<string, any>;
key: string | number | null;
children: VNode[];
dom: any | null;
text?: string | number;
parent?: VNode | null;
cleanup?: () => void;
};
type JSXChild = VNode | string | number | boolean | null | undefined | JSXChild[];
type JSXChildren = JSXChild;
type JSXElement = VNode | string | number | boolean | null;
Component-system helper types
Helper types from component-types.ts. SetupContext and MountContext are augmentation points.
type ViewFn = () => JSXElement | JSXElement[] | undefined;
type SetupFn<TProps, TEvents, TRef, TSlots> =
(ctx: ComponentSetupContext<PlatformElement, TProps, TEvents, TRef, TSlots>) => ViewFn | Promise<ViewFn>;
interface ComponentOptions { name?: string; }
type PropsAccessor<TProps> = { readonly [K in keyof TProps]: TProps[K] };
type SlotsObject<TSlots = {}> = { default: () => JSXElement[] } & TSlots;
type EmitFn<TEvents> = <TName extends keyof TEvents>(eventName: TName, ...args: any[]) => void;
interface MountContext<TElement = PlatformElement> { el: TElement; }
interface SetupContext {}
type PropsWithDefaults<TProps, D> = { readonly [K in keyof TProps]-?: K extends keyof D ? NonNullable<TProps[K]> : TProps[K] };
type Ref<T> = { current: T | null } | ((instance: T | null) => void);
type Exposed<T extends { __ref: any }> = T['__ref'];
type ComponentRef<T extends { __ref: any }> = Ref<T['__ref']>;
Platform types
Module-augmentation hooks: platforms set the element type; packages add global component attributes.
interface PlatformTypes {} // platforms declaration-merge `element: HTMLElement`
type PlatformElement = PlatformTypes extends { element: infer E } ? E : any;
interface ComponentAttributeExtensions {} // augmented by SSR to add 'client:load', etc.
Directive types
Directive lifecycle hook types. DirectiveDefinitionExtensions is an augmentation point (e.g. SSR getSSRProps).
interface DirectiveBinding<T = any> { value: T; oldValue?: T; }
interface DirectiveDefinitionExtensions<T = any> {}
interface DirectiveDefinition<T = any, El = any> extends DirectiveDefinitionExtensions<T> {
created?(el: El, binding: DirectiveBinding<T>): void;
mounted?(el: El, binding: DirectiveBinding<T>): void;
updated?(el: El, binding: DirectiveBinding<T>): void;
unmounted?(el: El, binding: DirectiveBinding<T>): void;
}
type ResolvedDirective<T = any, El = any> = [DirectiveDefinition<T, El>, T];
AsyncState
The reactive result of useData (and, via all, the combined state), plus the match arm table, the shared fetcher shape, and the read options. value is SWR last-good (kept across a same-key refresh(), cleared on key change); loading is state === 'pending' only; refresh() never rejects (failures land on .error).
type AsyncStateName = 'idle' | 'pending' | 'ready' | 'refreshing' | 'errored';
interface AsyncState<T> {
readonly state: AsyncStateName;
readonly value: T | null;
readonly error: Error | null;
readonly loading: boolean; // state === 'pending' ONLY
match<R>(arms: MatchArms<T, R>): R | undefined;
refresh(): Promise<void>; // never rejects
}
interface MatchArms<T, R> {
idle?: () => R; // defaults to `pending`
pending?: () => R; // omitted ⇒ renders nothing
error?: (e: Error, retry: () => void, stale: T | null) => R; // omitted ⇒ bubbles to errorScope / app onError
ready: (v: T) => R; // required — the only route to a non-null T
}
type Fetcher<T, Arg> = (arg: Arg, ctx: AsyncFetcherContext) => Promise<T>;
interface AsyncFetcherContext { signal: AbortSignal; } // pass to fetch(url, { signal })
interface AsyncOptions { server?: boolean; } // default true; false ⇒ client-only keyed read
AsyncAction / RunResult / AllState
The useAction handle, its settled result, and the combined all() state.
interface AsyncAction<T, In> {
readonly state: 'idle' | 'pending' | 'ready' | 'errored';
readonly value: T | null;
readonly error: Error | null;
readonly loading: boolean; // state === 'pending'
match<R>(arms: MatchArms<T, R>): R | undefined;
run(input: In): Promise<RunResult<T>>; // never rejects
reset(): void;
}
type RunResult<T> = { ok: true; value: T } | { ok: false; error: Error };
interface AllState<T, E> extends AsyncState<T> {
readonly errors: E; // collect-all counterpart to first-error-wins `.error`
}
interface ActionOptions {} // open interface — empty in core; packs augment it
LazyComponentFactory / DeferProps
Lazy-loading types.
type LazyComponentFactory<T extends AnyComponentFactory> = T & {
preload: () => Promise<T>;
isLoaded: () => boolean;
__lazy: true;
};
type DeferProps = Define.Prop<'fallback', JSXElement | (() => JSXElement)> & Define.Slot<'default'>;
InjectableFunction / SetupFactoryContext
Dependency-injection types. InjectableFunction is what defineInjectable returns and what defineProvide / app.defineProvide accept.
interface InjectableFunction<T> {
(): T;
_factory: () => T;
_token: symbol;
}
type FactoryFunction<TArgs extends unknown[], TInstance> =
((...args: TArgs) => TInstance) & { _factory: () => TInstance; _token: symbol };
interface SetupFactoryContext {
onDeactivated(fn: () => void): void;
subscriptions: SubscriptionHandler;
overrideDispose(onDispose: (fn: () => void) => void): void;
}
FactoryFunction is what a parameterized defineFactory returns — callable with the setup's params and carrying the provide metadata so it works with defineProvide / app.defineProvide.
Subscription / Topic / ModelProcessor / ComponentPlugin
Messaging, model-processor, and plugin types. ModelProcessor is the signature of an intrinsic-element model handler — register one with registerModelProcessor. ComponentPlugin is a type-only public export (its setter is internal).
interface Subscription { unsubscribe(): void; }
interface Topic<T> {
/** Tooling metadata (set via createTopic options). */
readonly namespace?: string;
readonly name?: string;
readonly subscriberCount: number;
readonly hasSubscribers: boolean;
readonly disposed: boolean;
publish(data: T): void;
subscribe(handler: (data: T) => void): Subscription;
destroy(): void;
}
type ModelProcessor = (type: string, props: Record<string, any>, modelBinding: [Record<string, any>, string], originalProps: Record<string, any>) => boolean;
type ComponentPlugin = { onDefine?: (name: string | undefined, factory: Function, setup: Function) => void };
ModelBinding / EventDefinition
type ModelBinding<_T> = [object, string];
type EventDefinition<T> = { __eventDetail: T };
See also
- Usage guide — practical patterns and examples.
- Overview — package summary and installation.
