API / @aihu/runtime

@aihu/runtime

Runtime core

Single File Component (.aihu) runtime — registers custom elements compiled by @aihu/compiler.

version
6.1.0
exports
51
values
36
types
15
01

_ensureA11yStyles

function
function _ensureA11yStyles(): void
02

_hmrReplace

function
function _hmrReplace(element: HTMLElement, newSetup: Setup): void
03

_inSsrLifecycle

function
function _inSsrLifecycle(): boolean

Is a server render currently running setup on this thread?

04

_registerAgentDispatcher

functionagent
function _registerAgentDispatcher( element: Element | null | undefined, dispatcher: InstanceAgentDispatcher, ): void

Register a mounted instance's agent dispatcher.

05

_registerAgentServerBinding

functionagent
function _registerAgentServerBinding( element: Element | null | undefined, binding: InstanceAgentServerBinding, ): void

Register a mounted instance's FULL server agent binding.

06

_setHydrate

function
function _setHydrate(fn: HydrateFn | null): void
07

_setMount

function
function _setMount(fn: MountFn): void
08

_setSignal

function
function _setSignal(s: typeof SignalFactory): void
09

_takeAgentDispatcher

function
function _takeAgentDispatcher( element: Element | null | undefined, ): InstanceAgentDispatcher | undefined

Look up the instance dispatcher registered for `element` (the mounted host custom element).

10

_takeAgentServerBinding

function
function _takeAgentServerBinding( element: Element | null | undefined, ): InstanceAgentServerBinding | undefined

Take (read) the server binding registered for `element`.

11

_withOwnerContext

function
function _withOwnerContext<R>(node: object, fn: () => R): R
12

_withSsrLifecycle

function
function _withSsrLifecycle<R>(fn: () => R): R

Run `fn` inside a server-render lifecycle window.

13

announce

function
function announce(message: string): void

Programmatic ARIA announcement.

14

createFocusTrap

function
function createFocusTrap( active: boolean | (() => boolean), returnFocus: boolean, initialFocus: string | null, childFn: () => Branch, ): Branch

Focus-trap boundary.

15

createResource

function
function createResource<T>(factory: () => Promise<T>): ResourceHandle<T>

Create a reactive resource backed by an async `factory`.

16

createStream

function
function createStream(factory: () => Promise<ReadableStream<string> | null>): StreamHandle

Create a reactive stream handle backed by a `ReadableStream<string>` factory.

17

defineComponent

function
function defineComponent(setupOrOptions: Setup | ComponentOptions): typeof HTMLElement
18

defineElement

function
function defineElement( name: string, Ctor: typeof HTMLElement, options?: DefineOptions, ): void
19

onAdopt

function
function _onAdopt(fn: () => void): void
20

onAttributeChange

function
function _onAttributeChange( fn: (name: string, oldValue: string | null, newValue: string | null) => void, ): void
21

onCleanup

function
function _onCleanup(fn: () => void): void
22

onCommit

function
function _onCommit(fn: () => void | (() => void)): void

Run `fn` after the browser's next layout opportunity, before paint.

23

onMount

function
function _onMount(fn: () => void | (() => void)): void
24

__aihu_cpath

const
const __aihu_cpath = (p: string): string => …

Comment-safe path for structural markers — the walker's `_commentPath` (`-` → `_` so arbitrary list keys can't terminate the comment early).

25

__aihu_eattr

const
const __aihu_eattr = (v: unknown): string => …

Attribute-value escape (`&` and `"`), the walker's `escapeAttr`.

26

__aihu_key

const
const __aihu_key = (v: unknown): string => …

List-item key normalization — the walker's `String(key).replace(/\./g, '_')` (dots would splice into the path grammar; see `_structuralSubtrees` in

27

__aihu_sattr

const
const __aihu_sattr = (k: string, v: unknown): string => …

One serialized attribute (` k="v"` / ` k` / nothing), mirroring the walker's `serializeAttrs` value rules for a RESOLVED value: functions (event handlers) never serialize, `true` renders the bare attribute, `false`/`undefined` render nothing, everything else stringifies escaped.

28

__aihu_schild

const
const __aihu_schild = (tag: string, attrsHtml: string, opts?: SsrChildRenderOpts): string => …

Render a referenced child component, or emit the empty element unchanged.

29

__aihu_stext

const
const __aihu_stext = (v: unknown): string => …

Escaped text hole for a REACTIVE leaf — the walker reads `String(get())`, so `null`/`undefined` stringify ("null"/"undefined"), exactly like a client-side reactive text binding would render them.

30

__aihu_stext0

const
const __aihu_stext0 = (v: unknown): string => …

Escaped text hole for an EAGER leaf — the walker's `leafText` renders nullish static values as the empty string.

31

_hydrateOnVisible

const
const _hydrateOnVisible = (element: HTMLElement, hydrate: () => void): void => …
32

_isSerializableAttrName

const
const _isSerializableAttrName = (k: string): boolean => …

Is `k` safe to serialize as an attribute name?

33

_MAX_CHILD_BYTES

const
const _MAX_CHILD_BYTES

Total child markup allowed per top-level render.

34

_MAX_CHILD_DEPTH

const
const _MAX_CHILD_DEPTH

Belt-and-braces bound on nesting.

35

_ssrChildWrap

const
const _ssrChildWrap = (tag: string, attrsHtml: string, mod: SsrChildModule, inner: string, hydratable: boolean): string => …

Wrap a child's rendered INNER markup in its host element.

36

SHADOW_ROOT_MODE

const
const SHADOW_ROOT_MODE

The DOM `ShadowRootMode` aihu attaches with — the SINGLE SOURCE for that value across the whole framework.

37

ComponentOptions

interface
interface ComponentOptions<A extends ReadonlyArray<string> = ReadonlyArray<string>> {
  attrs?: A
  /**
   * R1 ($prop reactivity, template-syntax-v2 round 5): rich per-prop
   * metadata bag describing the Lit-style `attribute` / `reflect` /
   * `converter` lowering. When non-empty, the runtime synthesizes
   * `observedAttributes` from prop entries with `attribute !== false`,
   * wires `attributeChangedCallback`, allocates one `Signal` per prop
   * initialized to `value`, defines a JS property accessor on the class
   * prototype, and (when `reflect: true`) reflects signal writes back to
   * the attribute with a re-entrancy guard.
   *
   * Value flows through to the setup function via `ctx.props.<name>`,
   * a per-name `Signal<unknown>`. Setup callers are expected to read via
   * the signal-getter call (e.g. `props.title()`); writes via
   * `props.title.set(...)` or via the JS property accessor on the host
   * element (`el.title = newValue`) flow back through the same signal.
   */
  props?: PropsConfig
  /**
   * Recipe class-extension (master spec §9.4): the generated element class
   * extends this base custom-element class instead of `HTMLElement`, so the
   * base's `connectedCallback` (role/ARIA/keyboard, form-control inheritance,
   * cross-piece context provision) runs on the host. Emitted by the compiler's
   * `$extends:` macro. Options-form only — base-extending recipes always carry
   * `$prop` declarations, so they compile to the options-form. The base's
   * `connectedCallback` runs BEFORE the template mounts (so a context-providing
   * primitive registers before its slotted child pieces upgrade), and its
   * `disconnectedCallback` runs on teardown; `observedAttributes` are unioned
   * and `attributeChangedCallback` is forwarded to the base.
   */
  base?: typeof HTMLElement
  setup: (ctx: SetupContext & AttrContext<A> & PropsContext) => Branch | Leaf
}

Options passed to the overloaded `defineComponent` when typed `observedAttributes` + per-attribute signals are desired.

38

DefineOptions

interface
interface DefineOptions {
  shadowMode?: ShadowMode
  /**
   * D5 `$form` — register as a form-associated custom element. The flag has to
   * reach the constructor BEFORE `customElements.define` runs: the definition
   * algorithm reads `formAssociated` off the constructor once, at define time,
   * so assigning the static afterwards is silently ignored.
   */
  formAssociated?: boolean
  /**
   * Light-DOM leaf flip (LDF §10 step 3) — the compiler-computed 8-hex-char
   * scope id this component's authored CSS is `@scope`d to
   * (`aihu-css-core`'s `light_scope.rs`). `define-element.ts`'s `wrapClass`
   * stamps it as `data-a="<id>"` on the element itself at construction time,
   * ONLY when `shadowMode` is `'light'` — a shadow-mode component has no use
   * for it (shadow DOM already provides real scoping).
   */
  lightScopeId?: string
}
39

InstanceAgentDispatcher

interface
interface InstanceAgentDispatcher {
  readonly tag: string
  /** opaqueId → action invoker (called with the positional args array). */
  readonly actions: Record<string, (args: unknown[]) => unknown>
  /** opaqueId → read accessor (current signal value). */
  readonly reads: Record<string, () => unknown>
  /** opaqueId → write accessor. */
  readonly writes: Record<string, (value: unknown) => void>
}

The instance-bound dispatcher shape.

40

InstanceAgentServerBinding

interfaceagent
interface InstanceAgentServerBinding {
  readonly tag: string
  /** memberName → action invoker (called with the positional args array). */
  readonly actions: Record<string, (args: unknown) => unknown>
  /** memberName → read accessor (current signal/computed value). */
  readonly reads: Record<string, () => unknown>
  /** memberName → write accessor (prop signal setter). */
  readonly writes: Record<string, (value: unknown) => void>
  /** `$scope` from the `@agent` block, or undefined when unscoped. */
  readonly scope: string | undefined
  /** `$rate-limit` as `'<n>/min'`, or undefined when unlimited. */
  readonly rateLimit: string | undefined
}

The full, per-instance agent binding the SERVER build injects into the setup body.

41

PropDef

interface
interface PropDef {
  value?: unknown
  attribute?: boolean | string
  reflect?: boolean
  converter?: (raw: string | null) => unknown
}

R1 — single `$prop` definition.

42

PropSignal

interfaceagent
interface PropSignal {
  (): unknown
  set(v: unknown): void
}

R1 — per-prop signal handle exposed to setup.

43

ResourceHandle

interface
interface ResourceHandle<T> {
  /** True while a fetch is in flight (initial load or a refetch). */
  readonly loading: boolean
  /** The latest resolved value, or `null` before the first success. */
  readonly data: T | null
  /** The error from the most recent failed run, or `null`. */
  readonly error: Error | null
  /** Re-run the factory. Resolves when the run settles. */
  refetch(): Promise<void>
}
44

SetupContext

interface
interface SetupContext {
  readonly host: ShadowRoot | Element
  readonly element: HTMLElement
  readonly connected: () => boolean
}

Context passed to a `defineComponent` setup function.

45

SsrChildModule

interface
interface SsrChildModule {
  /** The compiled string renderer, `__ssrString(props, opts)`. */
  readonly __ssrString?: (props: unknown, opts?: SsrChildRenderOpts) => string
  /**
   * The module's default export — the host-less `__ssr` factory the server
   * target emits (`export default __ssr`), which builds an arbor tree from a
   * setup run with empty props.
   *
   * Declared here purely so `@aihu/server`'s walker can reach it under
   * `AIHU_SSR_STRING=0`, where the point is NOT to use the compiled string
   * renderer. Nothing in this module calls it — it is synchronous to build but
   * the walk over its result is async, and everything here is synchronous by
   * construction. `unknown` rather than a factory type because that is all this
   * module can honestly assert about it.
   */
  readonly default?: unknown
  /** `__aihu_light_scope__` — the compiler-assigned light-DOM scope id. */
  readonly __aihu_light_scope__?: string
  /**
   * `__aihu_shadow__` (#770). aihu's OWN vocabulary — `'light' | 'shadow'` —
   * never the DOM's `ShadowRootMode`.
   */
  readonly __aihu_shadow__?: ShadowMode
  /**
   * `__aihu_css__` — the component's own CSS as a plain string.
   *
   * Used ONLY on the shadow path, where it is inlined as `<style>` inside the
   * declarative template. A shadow root is style-isolated by construction, so
   * prerendered markup whose styles are not inside it paints unstyled until the
   * component's chunk loads — the #754 failure, where content rendering ahead
   * of its scoped CSS pushed the LCP element below the fold.
   *
   * Light-DOM children ignore it: their rules arrive through the app
   * stylesheet's `@scope([data-a=…])` blocks (#758).
   */
  readonly __aihu_css__?: string
}

A compiled `--target server` module, as far as child rendering cares.

46

SsrChildRenderOpts

interface
interface SsrChildRenderOpts {
  readonly hydratable?: boolean
  readonly lightScopeId?: string
  /**
   * tag → compiled module, PRE-RESOLVED by the caller (SSG prerender or the
   * Workers handler). A Map and not a callback on purpose: module loading is
   * async while this path is synchronous, and hoisting resolution to the caller
   * is what lets the compiled fast path survive child rendering at all. It is
   * also where the cycle guard belongs — once, over the whole graph, at build
   * time, rather than at every render.
   */
  readonly children?: ReadonlyMap<string, SsrChildModule>
  /** @internal Recursion depth, incremented per nested child. */
  readonly __depth?: number
  /**
   * @internal Per-render memo of already-serialized children, keyed by tag +
   * hydration mode.
   *
   * Bounds FAN-OUT, which the depth cap alone does not. A depth cap limits how
   * DEEP the recursion goes, not how WIDE: with each of 14 components
   * referencing the next three times, a perfectly acyclic graph expands to
   * 3^13 renders — measured at 67 MB of output in 0.2 s, and tens of GB a few
   * components later. The cycle guard cannot see this either, because
   * `__aihu_child_tags__` is a SET while the emitter emits one call per
   * reference site.
   *
   * Safe because a child render is deterministic within one top-level render:
   * it always receives `{}` props, `lightScopeId: ''`, and the same registry,
   * and its tree restarts at ROOT_PATH behind its own `data-aihu-ssr` boundary,
   * so two reference sites legitimately produce identical inner markup. Scoped
   * PER RENDER, not module-global — component setup can read stores or context
   * that differ between requests.
   */
  readonly __memo?: Map<string, string>
  /**
   * @internal Remaining child expansions for this top-level render.
   *
   * The memo bounds the WORK of fan-out; it cannot bound the OUTPUT. Three
   * references repeated 13 deep is 3^13 reference sites, and each legitimately
   * emits the child's markup — memoized, that is 89 MB in 16 ms rather than
   * 67 MB in 217 ms. Faster, and still a build-killer.
   *
   * So the budget counts BYTES, not expansions. Counting expansions does not
   * work once the memo exists: only one render happens per tag, but each
   * RETURNS three times its child's string, so output grows exponentially
   * while the render count stays linear — measured at 89 MB from 14 renders.
   * Bytes are the thing that actually gets large, so bytes are what is bounded.
   *
   * Past the budget a reference renders as the empty element it rendered before
   * this feature existed: degraded, loudly reported, and finite.
   */
  readonly __budget?: { bytes: number; reported: boolean }
}

The opts a compiled `__ssrString` accepts, plus the child registry.

47

StreamHandle

interface
interface StreamHandle {
  readonly value: string
  readonly delta: string
  readonly status: StreamStatus
  readonly error: Error | null
  start(
    source?: ReadableStream<string> | (() => Promise<ReadableStream<string> | null>),
  ): Promise<void>
  stop(): void
}
48

PropsConfig

type
type PropsConfig = Record<string, PropDef>
49

Setup

type
type Setup = (ctx: SetupContext) => Branch | Leaf

A `defineComponent` setup function: receives a `SetupContext`, returns the arbor tree to mount.

50

ShadowMode

type
type ShadowMode = 'light' | 'shadow'

Rendering mode for the custom element — a BINARY choice (DA4 #437).

51

StreamStatus

type
type StreamStatus = 'idle' | 'streaming' | 'done' | 'error'