# VSN.js runtime API

Use explicit JavaScript setup when you need control over registration, mounting, hydration, or extensions. [CFS](/reference/cfs) defines the behavior source; [plugins](/reference/plugins) add optional features.

## Engine

Import public APIs from `vsn` in a bundled application:

```js
import { Engine, parseCFS } from "vsn";

const source = "#counter { count: 0; }";
const program = parseCFS(source);
const engine = new Engine({ diagnostics: true });
engine.registerBehaviors(source);
await engine.mount(document.getElementById("counter"));
```

`parseCFS(source: string)` parses source into a program AST. It does not mount anything or inherit an engine's registered flags. For behavior source using runtime event flags or custom extensions, use `engine.registerBehaviors()` with the relevant registrations in place. `Lexer`, `Parser`, `TokenType`, AST exports, and `VERSION` are also exported for tooling.

### Initialization and teardown

| API | Return / behavior |
| --- | --- |
| `new Engine(options?)` | Create an engine |
| `registerBehaviors(source: string)` | Parse and register CFS source |
| `mount(root: HTMLElement)` | `Promise<void>`; initialize and observe the root |
| `hydrate(root: HTMLElement, { state }?)` | `Promise<void>`; initialize with optional root state and preserve uninitialized SSR values |
| `unmount(element: Element)` | Tear down bindings for the subtree |
| `dispose()` | Tear down mounted roots and engine-owned resources |
| `signal` | Engine lifetime's `AbortSignal` |
| `getScope(element, parentScope?)` | Get or create an element's `Scope` |
| `getLifetime(element)` | Element inline-binding `Lifetime` |
| `evaluate(element)` | Re-evaluate the element's registered bindings |
| `getRegistryStats()` | `{ behaviorCount, behaviorCacheSize }` |

`EngineOptions` accepts `diagnostics`, `logger` (optional `info` and `warn` methods), `htmlSanitizer`, `trustedTypesPolicy`, and `trustedTypesPolicyName`. A sanitizer has the signature `(html: string) => string`. A supplied Trusted Types policy provides `createHTML(value: string)`.

`autoMount(root?: HTMLElement | Document): Engine | null` sets up automatic source loading and mounting, with `document` as its browser default. It returns the engine before asynchronous mounting completes. It applies registered browser plugins, loads inline and external `text/vsn` scripts, and mounts the body or supplied element. Use explicit `mount()` when you need an awaitable initialization step.

### Globals and extensions

| API | Purpose |
| --- | --- |
| `registerGlobal(name, value)` | Expose a value to CFS |
| `registerGlobals(values)` | Expose a record of values |
| `registerFlag(name, handler?)` | Register declaration/event flag hooks |
| `registerBehaviorModifier(name, handler?)` | Register behavior lifecycle hooks |
| `registerAttributeHandler(handler)` | Register a custom attribute handler |
| `registerHtmlTransformer(transform, { priority }?)` | Transform HTML values; returns a removal function |
| `registerHtmlSanitizer(sanitizer)` | Replace the sanitizer; returns a restoration function |

An attribute handler supplies `id`, `match(name)`, and `handle(element, name, value, scope, context?)`. A handler with the same ID replaces the previous handler. Its context includes `lifetime`, `signal`, `hydrating`, and `onCleanup`.

Behavior modifier hooks are `onBind`, `onConstruct`, `onDestruct`, and `onUnbind`. The names `important` and `debounce` are reserved for behavior modifier registration. Flag hooks include `onApply`, `transformValue`, `onEventBind`, `onEventBefore`, `onEventAfter`, and `transformEventArgs`. Register custom flags and modifiers before parsing behavior source that uses them.

HTML transformers receive `(value, { element, trusted })`; lower priority runs first, with registration order breaking ties. Use lifetime cleanup for resources created by extensions.

### HTML and requests

`setHtml(element, value, { trusted?, process? }?)` transforms and inserts HTML. Untrusted output is sanitized. Processing is enabled unless `process` is `false`.

`processHtml(root, { trusted? }?)` processes dynamic HTML within a root. Only use `trusted: true` for application-controlled content. [HTML safety guide](/guide#safe-dynamic-html).

`request(element, config): Promise<RequestResult>` sends a request and optionally applies its HTML response. `RequestConfig` accepts:

```ts
{
  url?: string;
  method?: string;
  headers?: HeadersInit;
  body?: unknown;
  form?: HTMLFormElement;
  submitter?: HTMLElement;
  targetSelector?: string;
  swap?: "inner" | "outer" | "none";
  trusted?: boolean;
  history?: "none" | "push" | "replace";
  historyUrl?: string;
  restoreFocus?: boolean | string;
  signal?: AbortSignal;
}
```

The result contains `response: Response`, `body: string`, `target: Element | null`, and `swapped: boolean`. `GetConfig` is a backward-compatible alias for `RequestConfig`. HTTP failures use the exported `RequestError`, with `response`, `status`, `statusText`, and `url` fields.

## Scope and reactivity

The core exports `Scope`, `batch`, `computed`, and `effect` for JavaScript integrations:

```js
import { Scope, batch, computed, effect } from "vsn";

const scope = new Scope();
scope.set("count", 0);
const doubled = computed(scope, s => s.get("count") * 2);
const stop = effect(scope, s => {
  console.log(s.get("count"), doubled.value);
});

batch(() => {
  scope.set("count", 1);
  scope.set("count", 2);
});

stop();
doubled.dispose();
```

| API | Purpose |
| --- | --- |
| `new Scope(parent?)` | Create a scope with an optional parent |
| `scope.createChild()` | Create an inheriting child |
| `scope.get(path)` / `getPath(path)` | Read a scope path |
| `scope.set(path, value)` / `setPath(path, value)` | Write a scope path |
| `scope.getLocal(name)` / `setLocal(name, value)` | Access local state |
| `scope.on(path, handler)` / `off(path, handler)` | Add/remove a path listener |
| `scope.onAny(handler)` / `offAny(handler)` | Add/remove a scope-wide listener |
| `batch(callback)` | Batch reactive updates; returns the callback's result |
| `computed(scope, getter, options?)` | Create a dependency-tracked computed reference |
| `effect(scope, callback, options?)` | Run a dependency-tracked effect; return a disposer |

A computed reference exposes read-only `value`, `get()`, `subscribe(listener)`, and `dispose()`. `subscribe` returns a disposer. Computed options accept a `lifetime`.

`scope.computed(getter, options?)` is the scope-bound form. `scope.computed(name, getter, options?)` also exposes a named computed value on the scope; the name must be an unused, nonempty root key without dots. `scope.effect(callback, options?)` binds an effect to that scope.

An effect callback receives the scope and may return a cleanup function. Effect options accept `lifetime` and a `scheduler(run)` that may return a disposer. The engine also exposes `batch(callback)`, `computed(scope, getter, options?)`, and `effect(scope, callback, options?)`.

`Lifetime`, `isAbortError`, `throwIfAborted`, and the `Disposer` type are exported for lifecycle-aware integrations. Tie external subscriptions and asynchronous work to the relevant lifetime rather than leaving them running after unmount.

