Askr
Reference

Behavioral Contracts

Use behavioral contracts with the current published Askr packages.

  • @askrjs/askr0.0.59

How to use behavioral contracts

Preserve ownership, cancellation, deterministic rendering, and delivery parity when composing lower-level APIs into application features.

  1. Import the published @askrjs/askr entrypoint.
  2. Keep behavioral contracts configuration next to the component, route, or server composition root that owns it.
  3. Handle pending, unavailable, cancellation, and failure states, then verify the production path.
import { resource } from '@askrjs/askr/resources';

const project = resource(
  ({ signal }) => api.projects.get(projectId(), { signal }),
  [projectId]
);

// The component owns this request; disposal aborts it.

Render contract

A component function is a `ComponentFunction`: it takes `Props` and an optional `ComponentContext` (carrying a `signal` and, during SSR, an `SSRContext`) and returns a `JSXElement` or `VNode`. Calling `state()` is only valid during that render call — it reads the active component instance from context, and calling it outside a component function throws, per the runtime's own guard.

Ownership

Reactive scope is threaded with `defineScope()`/`readScope()` rather than any global mutable state — `defineScope(defaultValue)` creates a `Scope<T>` you provide via a wrapping element, and `readScope()` reads the nearest value down the component tree. Internally each mounted component tracks its own `ownerFrame`, `stateValues`, and cleanup functions, so state and scope values are torn down with the instance that created them.

Cancellation

Every component receives an `AbortSignal` through its render context, and `ComponentInstance` holds the backing `AbortController` used to cancel in-flight work when the component unmounts. `resource()` (from @askrjs/askr/resources) is built on this — it passes the signal into your async function so a `fetch` or other cancelable call stops when the component goes away, instead of resolving into a dead component.

Delivery parity

The same component tree renders through server rendering (SSR), static generation (SSG), and client hydration via a shared `DocumentRenderContext` (mode, url, params, seed, route) — the framework doesn't fork behavior between server and client render paths. Hydration reconciles the server-rendered markup against the client's first render pass rather than re-rendering from scratch, so component output needs to be stable across both invocations for hydration to succeed cleanly.